--------------------------------------------------------------------------------
ROM CODE如何从MMC启动
--------------------------------------------------------------------------------
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)0](https://i-blog.csdnimg.cn/blog_migrate/3d111349673ae853aeb56a124fc78dfd.png)
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)1](https://i-blog.csdnimg.cn/blog_migrate/d75007c0b87a3f057a0c74ea8c419cf4.png)
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)2](https://i-blog.csdnimg.cn/blog_migrate/8e28ee53783739b796b26b6c8926e1f0.png)
ROM code将boot parameters的结构体指针通过R0寄存器传递给MLO,在start.s的reset部分,第一句
指令就是:bl save_boot_params.
5.07版本中相关代码比较复杂,而7.00中就相对简单:
就是将R0的数据存储到r1所指的地址中,仅仅存储了一个指针就返回了。
-------------------------------------------------------------------------
Start.s Start
-------------------------------------------------------------------------
位于arch/arm/cpu/armv7/start.s
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)3](https://i-blog.csdnimg.cn/blog_migrate/cf10bb3e379eb3c178a0ec8a94493460.png)
上电直接跳到reset异常处理例程
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)4](https://i-blog.csdnimg.cn/blog_migrate/25307c685adae970375a1ad7bea6d5c3.png)
bl save_boot_params
调用save_boot_params,保存boot参数,不详述。continue...
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)5](https://i-blog.csdnimg.cn/blog_migrate/a38719c350f7a9f0caae1d94873a4464.png)
bl cpy_clk_code
cpy_clk_code是将DPLL的代码拷贝到SRAM中,暂不述。
bl cpu_init_crit
bl cpu_init_crit
cpu_init_crit只在SPL阶段会被调用,用于setup important registers and memory timing.
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)6](https://i-blog.csdnimg.cn/blog_migrate/4ae05b8ac03db9b73f220bdd26bbf895.png)
bl board_init_f
接着调用lowlevel_init函数,位于arch/arm/cpu/armv7/omap-common/lowlevel_init.s文件。
relocate_code
clear_bss
board_init_r
relocate_code
clear_bss
board_init_r
从名字可以看出,该文件用于底层的初始化。
--------------------------------------------------------------------------------
lowlevel_init Start(lowlevel_init.s)
--------------------------------------------------------------------------------
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)7](https://i-blog.csdnimg.cn/blog_migrate/b35a8ca9d73350107cff0f9c57a0029f.png)
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)8](https://i-blog.csdnimg.cn/blog_migrate/0e165b3fd507ab18f470ad894ba9fc62.png)
这里首先建立一个临时的栈,用于运行接下来c程序s_init。其中LOW_LEVEL_SRAM_STACK定义在asm/arch/omap.h文件里面。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)9](https://i-blog.csdnimg.cn/blog_migrate/0aac2320fee3f070ef54506c3e39cb00.png)
而0x4030B7FC位于MPU的L3 OCMC0区域。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)10](https://i-blog.csdnimg.cn/blog_migrate/85e68e131ed08e4fb6522f8ed064e205.png)
调用的函数s_init,位于board/ti/am335x/evm.c下。
在s_init中有几步很关键
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)11](https://i-blog.csdnimg.cn/blog_migrate/4008f469b4d0f6f99d3f65bd5765c8bd.png)
1、 preloader_console_init()用于初始化串口,调用serial_init(),该函数位于common/serial.c文件里面。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)12](https://i-blog.csdnimg.cn/blog_migrate/7f6b4aca441a3177b077bfc69775c375.png)
serial_init()函数首先检查当前有没有串口,显然没有,就只能用 默认串口 default_serial_console结构。该结构定义在drivers/serial/serial.c中。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)13](https://i-blog.csdnimg.cn/blog_migrate/24f9f1ebc05ce6b3f0d36621aaffc3f0.png)
其中CONFIG_CONS_INDEX宏定义在include/configs/am335x_evm.h,定义为1表示使用UART0口。
这块是移植时候需要注意的地方,否则调试u-boot时候在默认的串口上不会打印信息。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)14](https://i-blog.csdnimg.cn/blog_migrate/d802a509de45c9f3f8ebc1d5195d3db8.png)
2、 enable_i2c0_pin_mux() i2c_init()以及read_eeprom(),这三个函数主要适用于TI公司AM335x相关的板子。
这一系列板子上面都有EEPROM并且存储了板子的信息,read_eeprom用于读取相关信息。
s_init C ontinue...
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)15](https://i-blog.csdnimg.cn/blog_migrate/07fb8eb97cccebc64dc132f801ca5843.png)
定义变量is_ddr3用于选择初始化的对象,这也是移植时候需要注意的地方。
--------------------------------------------------------------------------------
lowlevel_init End(lowlevel_init.s)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
call_board_init_f Start(start.s)
--------------------------------------------------------------------------------
Back to start.s
调用完cpu_init_crit后,start.s会继续,接着会调用board_init_f(),在调用之前会在内部SRAM中设立栈指针,
这样才能调用函数,因为函数调用需要入栈的操作。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)16](https://i-blog.csdnimg.cn/blog_migrate/59ae904ac9616b5f90f9ce6725ae847f.png)
1、栈指针值CONFIG_SYS_INIT_SP_ADDR
start.s又包含 config.h 文件(位于am335x/include/config.h,am335x是编译时候生成的,Makefile将与目标板相关的文件集中在此处)
config.h文件内容:
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)17](https://i-blog.csdnimg.cn/blog_migrate/118d7241a424d289a5bef8f5ac60596e.png)
在configs/am335x_evm.h中定义了CONFIG_SYS_INIT_SP_ADDR:
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)18](https://i-blog.csdnimg.cn/blog_migrate/2294d6ec1b94f6b55f20b451481b5fc2.png)
即CONFIG_SYS_INIT_SP_ADDR = SRAM0_START + SRAM0_SIZE - GENERATED_GBL_DATA_SIZE
其中 SRAM0_START定义在hardware.h中,进入后可知 SRAM0_START = 0x402F0400,正是Memory Map中SRAM internel的首地址。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)19](https://i-blog.csdnimg.cn/blog_migrate/bac6ec7e0030bd94b5252bb66b4f78dd.png)
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)20](https://i-blog.csdnimg.cn/blog_migrate/e2911d873affb0bb1dac8b032cca4dc2.png)
SRAM0_SIZE定义在cpu.h中,进入后可知 SRAM0_SIZE = 0x1B400,这个SIZE一直将SRAM延伸到OCMC0里面,结束地址为0x4030B800。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)21](https://i-blog.csdnimg.cn/blog_migrate/65c67bd04d8b4a4524e7464c13ef4f2c.png)
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)22](https://i-blog.csdnimg.cn/blog_migrate/19b32d7fd42ffce539ec938ae6aceb4f.png)
GENERATED_GBL_DATA_SIZE定义在generic-asm-offset.h(asm-offset.h包含此头文件)中,值为128。
这个size的空间是用于存储global_data结构的数据,存储空间以16字节对齐(这个并未证明,因为代码里面没有在任何地方提到将全局变量指针指向此地)。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)23](https://i-blog.csdnimg.cn/blog_migrate/00b11acb36cf8fff5d03a10883a489a1.png)
总结一下 ,到这一步,在MPU的内部OCMC0区设置栈底SP = 0x4030B800 - 128 = 0x4030B780 ,并在栈底上面存储分配128 Bytes空间用于存储全局数据。
2、MLO重定位
board_init_f函数位于arch/arm/cpu/armv7/omap-common/spl.c。该函数唯一做的事情就是向relocate_code
函数传入三个参数,然后程序流程又回到start.s文件。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)24](https://i-blog.csdnimg.cn/blog_migrate/aa65b82e244a094dde9cfd0de5ceae8a.png)
在board_init_f()函数调用start.s中的relocate_code函数,这里实现重定位(实现机理可以百度之),
http://blog.csdn.net/zsy2020314/article/details/9824035 这个解释不错
重定位后,后面的puts不会运行了,因为relocate_code不会返回。见下图。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)25](https://i-blog.csdnimg.cn/blog_migrate/08dc90957548eae2f0ce6b8becae5d7d.png)
--------------------------------------------------------------------------------
relocate_code Start(start.s)
--------------------------------------------------------------------------------
relocate_code的代码如下:
/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
*/
.globl relocate_code
relocate_code:
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
/* Set up the stack */
stack_setup:
mov sp, r4
adr r0, _start
cmp r0, r6
moveq r9, #0 /* no relocation. relocation offset(r9) = 0 */
beq clear_bss /* skip relocation */
mov r1, r6 /* r1 <- scratch for copy_loop */
ldr r3, _image_copy_end_ofs
add r2, r0, r3 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r9-r10} /* copy from source address [r0] */
stmia r1!, {r9-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
blo copy_loop
#ifndef CONFIG_SPL_BUILD
/*
* fix .rel.dyn relocations
*/
ldr r0, _TEXT_BASE /* r0 <- Text base */
sub r9, r6, r0 /* r9 <- relocation offset */
ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */
add r10, r10, r0 /* r10 <- sym table in FLASH */
ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */
add r2, r2, r0 /* r2 <- rel dyn start in FLASH */
ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */
add r3, r3, r0 /* r3 <- rel dyn end in FLASH */
fixloop:
ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */
add r0, r0, r9 /* r0 <- location to fix up in RAM */
ldr r1, [r2, #4]
and r7, r1, #0xff
cmp r7, #23 /* relative fixup? */
beq fixrel
cmp r7, #2 /* absolute fixup? */
beq fixabs
/* ignore unknown type of fixup */
b fixnext
fixabs:
/* absolute fix: set location to (offset) symbol value */
mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */
add r1, r10, r1 /* r1 <- address of symbol in table */
ldr r1, [r1, #4] /* r1 <- symbol value */
add r1, r1, r9 /* r1 <- relocated sym addr */
b fixnext
fixrel:
/* relative fix: increase location by offset */
ldr r1, [r0]
add r1, r1, r9
fixnext:
str r1, [r0]
add r2, r2, #8 /* each rel.dyn entry is 8 bytes */
cmp r2, r3
blo fixloop
b clear_bss
_rel_dyn_start_ofs:
.word __rel_dyn_start - _start
_rel_dyn_end_ofs:
.word __rel_dyn_end - _start
_dynsym_start_ofs:
.word __dynsym_start - _start
#endif /* #ifndef CONFIG_SPL_BUILD */
clear_bss:
#ifdef CONFIG_SPL_BUILD
/* No relocation for SPL */
ldr r0, =__bss_start
ldr r1, =__bss_end__
#else
ldr r0, _bss_start_ofs
ldr r1, _bss_end_ofs
mov r4, r6 /* reloc addr */
add r0, r0, r4
add r1, r1, r4
#endif
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
jump_2_ram:
/*
* If I-cache is enabled invalidate it
*/
#ifndef CONFIG_SYS_ICACHE_OFF
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
mcr p15, 0, r0, c7, c10, 4 @ DSB
mcr p15, 0, r0, c7, c5, 4 @ ISB
#endif
ldr r0, _board_init_r_ofs
adr r1, _start
add lr, r0, r1
add lr, lr, r9
/* setup parameters for board_init_r */
mov r0, r5 /* gd_t */
mov r1, r6 /* dest_addr */
/* jump to it ... */
mov pc, lr
_board_init_r_ofs:
.word board_init_r - _start
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
*/
.globl relocate_code
relocate_code:
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
/* Set up the stack */
stack_setup:
mov sp, r4
adr r0, _start
cmp r0, r6
moveq r9, #0 /* no relocation. relocation offset(r9) = 0 */
beq clear_bss /* skip relocation */
mov r1, r6 /* r1 <- scratch for copy_loop */
ldr r3, _image_copy_end_ofs
add r2, r0, r3 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r9-r10} /* copy from source address [r0] */
stmia r1!, {r9-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
blo copy_loop
#ifndef CONFIG_SPL_BUILD
/*
* fix .rel.dyn relocations
*/
ldr r0, _TEXT_BASE /* r0 <- Text base */
sub r9, r6, r0 /* r9 <- relocation offset */
ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */
add r10, r10, r0 /* r10 <- sym table in FLASH */
ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */
add r2, r2, r0 /* r2 <- rel dyn start in FLASH */
ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */
add r3, r3, r0 /* r3 <- rel dyn end in FLASH */
fixloop:
ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */
add r0, r0, r9 /* r0 <- location to fix up in RAM */
ldr r1, [r2, #4]
and r7, r1, #0xff
cmp r7, #23 /* relative fixup? */
beq fixrel
cmp r7, #2 /* absolute fixup? */
beq fixabs
/* ignore unknown type of fixup */
b fixnext
fixabs:
/* absolute fix: set location to (offset) symbol value */
mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */
add r1, r10, r1 /* r1 <- address of symbol in table */
ldr r1, [r1, #4] /* r1 <- symbol value */
add r1, r1, r9 /* r1 <- relocated sym addr */
b fixnext
fixrel:
/* relative fix: increase location by offset */
ldr r1, [r0]
add r1, r1, r9
fixnext:
str r1, [r0]
add r2, r2, #8 /* each rel.dyn entry is 8 bytes */
cmp r2, r3
blo fixloop
b clear_bss
_rel_dyn_start_ofs:
.word __rel_dyn_start - _start
_rel_dyn_end_ofs:
.word __rel_dyn_end - _start
_dynsym_start_ofs:
.word __dynsym_start - _start
#endif /* #ifndef CONFIG_SPL_BUILD */
clear_bss:
#ifdef CONFIG_SPL_BUILD
/* No relocation for SPL */
ldr r0, =__bss_start
ldr r1, =__bss_end__
#else
ldr r0, _bss_start_ofs
ldr r1, _bss_end_ofs
mov r4, r6 /* reloc addr */
add r0, r0, r4
add r1, r1, r4
#endif
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
/*
* We are done. Do not return, instead branch to second part of board
* initialization, now running from RAM.
*/
jump_2_ram:
/*
* If I-cache is enabled invalidate it
*/
#ifndef CONFIG_SYS_ICACHE_OFF
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
mcr p15, 0, r0, c7, c10, 4 @ DSB
mcr p15, 0, r0, c7, c5, 4 @ ISB
#endif
ldr r0, _board_init_r_ofs
adr r1, _start
add lr, r0, r1
add lr, lr, r9
/* setup parameters for board_init_r */
mov r0, r5 /* gd_t */
mov r1, r6 /* dest_addr */
/* jump to it ... */
mov pc, lr
_board_init_r_ofs:
.word board_init_r - _start
从代码的最后可以看出来,最后mov pc,lr,是跳到重定位后的 board_init_r函数处。
代码还是那段代码,只是在内存中的位置变化了。
再回到board_init_f中调用relocate_code函数,传入三个参数:
relocate_code(CONFIG_SPL_STACK, &g_data, CONFIG_SPL_TEXT_BASE);
第一个参数是栈指针:CONFIG_SPL_STACK
第二个参数是全局数据结构指针:&g_data
第三个参数是重定位的目的地址:CONFIG_SPL_TEX_BASE
relocate_code的代码是用汇编书写的,这里要提到的是C参数如何传递给汇编语言的。这里必须要提到ABI和EABI,
ABI是Application Binary Interface的缩写,跟API很类似。但ABI是比API更贴近硬件的一层接口,它规定的
是二进制代码之间的调用规则。
我们知道API是与机器硬件平台无关的接口,如熟悉的printf函数,不同的库的实现可能是不同的,但是它们的接口名称
与参数类型都是一样的。ABI比API的要求更严格,它要求在寄存器级别遵守同样的接口规范,如函数调用的参数传递规则,
寄存器、堆栈的使用方式等。编译器被要求遵守同样的ABI规范,这样不同编译器编译出来的库(相同硬件)才能被别的
编译器使用。
EABI是使用与嵌入式场合的应用二进制接口。这里就简单提一下:函数调用时,传递的参数如果都小于32bit则使用
R0-R3传递参数,参数个数超出4个则使用STACK传递,因此为了代码的效率,程序员应该尽量保证将函数的参数个数限制
在4个以下。
对于CONFIG_SPL_STACK,是LOW_LEVEL_SRAM_STACK的宏定义。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)26](https://i-blog.csdnimg.cn/blog_migrate/d1250ce0c5efefd7ed3782e52e322217.png)
另外am335x_evm.h还包含hardware.h
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)27](https://i-blog.csdnimg.cn/blog_migrate/d2beef530bfe59391c145981c0515420.png)
hardware.h包含omap.h
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)28](https://i-blog.csdnimg.cn/blog_migrate/24ba00fb1ac07ec8a1ada971386431ec.png)
在omap.h中有LOW_LEVEL_SRAM_STACK的宏定义,这个宏定义和前文提到调用s_init函数前的建立栈底是一样的。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)29](https://i-blog.csdnimg.cn/blog_migrate/944ff7ba6b93f9f704712187257477e7.png)
由于栈生长的方向是向下的,所以栈底必须设置为高地址处,这个地址已经快接近OCMC0的底部。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)30](https://i-blog.csdnimg.cn/blog_migrate/634397f4907b6201826707cdcfe53e75.png)
对于 CONFIG_SPL_TEXT_BASE,正是MPU内部SRAM的起始地址。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)31](https://i-blog.csdnimg.cn/blog_migrate/43d575aee0732fc9ff0a416c422aec1d.png)
--------------------------------------------------------------------------------
relocate_code End (start.s)
--------------------------------------------------------------------------------
总结一下:从打印信息看,我们的板子的stack生长方向是递减的。
有一点很疑惑的是:在调用board_init_f之前,SP设置为0x4030B780,进入board_init_f后调用
relocate_code,传入的SP地址参数为0x4030B7FC,SP往上面移动了,这是为什呢?因为重定位后是不会从
relocate_code函数返回的,所以board_init_f的入栈参数会被抹掉但无所谓,但是能不能将这两次的SP设置成一样的呢?
(PS: TI-SDK-AM335X-EVM-07.00中堆栈的设置没有让人confused的地方了)
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)32](https://i-blog.csdnimg.cn/blog_migrate/87d7761035adefd5703ceb01eb3c1ea9.png)
--------------------------------------------------------------------------------
call_board_init_f End(start.s)
--------------------------------------------------------------------------------
board_init_f函数调用relocate_code,该函数实现代码的搬迁。从下面的图中可以看到:
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)33](https://i-blog.csdnimg.cn/blog_migrate/6ec5486061fac6c21d40a9b5e8fc8511.png)
_start处于内存位置:0x402F0400
在relocate_code中,
relocate_code:
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
stack_setup:
mov sp, r4
mov sp, r4
adr r0, _start
cmp r0, r6
moveq r9, #0 /* no relocation. relocation offset(r9) = 0 */
beq clear_bss /* skip relocation */
mov r1, r6 /* r1 <- scratch for copy_loop */
ldr r3, _image_copy_end_ofs
add r2, r0, r3 /* r2 <- source end address */
cmp r0, r6
moveq r9, #0 /* no relocation. relocation offset(r9) = 0 */
beq clear_bss /* skip relocation */
mov r1, r6 /* r1 <- scratch for copy_loop */
ldr r3, _image_copy_end_ofs
add r2, r0, r3 /* r2 <- source end address */
将_start加载到r0中,与r6比较,而r6是由r2传递过来的目标地址CONFIG_SPL_TEXT_BASE=0x402F0400。
因此会执行beq clear_bss处,即copy_loop的代码不会执行。
在代码里面加入宏开关,重新编译后依然能执行,证实了这个想法:
MLO阶段不会将自己copy到SRAM中,copy动作应该是由ROM Code实现的。
另外一个证明就是,ti-sdk-07.00版本的u-boot代码中明确了没有在MLO阶段调用relocate_code,仅仅在u-boot阶段调用。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)34](https://i-blog.csdnimg.cn/blog_migrate/75a0119b73f5a3e402d1c3100dd35e12.png)
-------------------------------------------------------------------------
Start.s End
-------------------------------------------------------------------------
--------------------------------------------------------------------------------
board_init_r Start(start.s)
--------------------------------------------------------------------------------
relocate_code结束的时候,跳到board_init_r函数处,该函数位于arch/arm/cpu/armv7/omap-common/spl.c。
该函数主要初始化内存、各个外设:
mem_malloc_init()
timer_init()
i2c_init()
spl_board_init()
然后选择从那个外设加载image。我们调试的时候从SD卡加载u-boot的image,所以关注spl_mmc_load_image函数。
--------------------------------------------------------------------------------
spl_mmc_load_image Start(board_init_r)
--------------------------------------------------------------------------------
首先取得boot_device的序号,这个序号是定义在boot_params结构体的第三个成员项
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)35](https://i-blog.csdnimg.cn/blog_migrate/47a8b41c8e379e8f03d3841c6ea7b691.png)
omap_boot_device函数定义在arch/arm/cpu/armv7/omap-common/boot-common.c中。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)36](https://i-blog.csdnimg.cn/blog_migrate/e7dc95a047355c781ed704fb7f61b429.png)
结构体omap_boot_parameters定义在
,这个定义与最开始
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)37](https://i-blog.csdnimg.cn/blog_migrate/fb646ee55eb59fc07839b3f5113b8011.png)
时候的Booting Parameters Structure是一致的。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)38](https://i-blog.csdnimg.cn/blog_migrate/2c59ae3ee0a3290295fb64ac809b1689.png)
将boot_device和boot_params的地址都打印出来,如下图所示:
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)39](https://i-blog.csdnimg.cn/blog_migrate/78d513d13ccf18ab1d7580edb5b50bde.png)
可以看到boot device是8,对应的是MMC/SD port 0设备,boot_params结构体的地址是0x40303990,位于L3 0CMC0存储区,很显然这个地址是由连接器分配的,位于“Downloaded Image”区域。
而在spl_mmc_load_image中最关键的部分是,
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)40](https://i-blog.csdnimg.cn/blog_migrate/dc0ac779f0c557916b1cf012e03710b7.png)
将boot_mode打印出来,2对应MMCSD_MODE_FAT模式。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)41](https://i-blog.csdnimg.cn/blog_migrate/c6f39eb9abae187e6a6d9ec771bc124d.png)
另外,由于代码的增加,这儿可以看到boot_params结构体的地址变成了0x403039B8。
而mmc_load_image_fat中最重要的代码就是解析header和读出image。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)42](https://i-blog.csdnimg.cn/blog_migrate/b67874582fb4e0d7287f67c50e5b4a62.png)
spl_parse_image_header将header的中信息解析出来放在结构体spl_image里面,file_fat_read函数将image读到spl_image.load_addr所指向的缓冲区。
--------------------------------------------------------------------------------
spl_mmc_load_image End(board_init_r)
--------------------------------------------------------------------------------
spl_image是很重要的一个结构体,将其打印出来看看有什么。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)43](https://i-blog.csdnimg.cn/blog_migrate/d81ad6345a318995cd342b70ea6f4c63.png)
spl_image的地址已经到了0x8000,0000,这已经是Externel SDRAM的首地址了。那么谁安排spl_image的地址的?
搜索一番,发现spl_image处于.bss区域,即未初始化区域,map里面将其放在0x8000000地址。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)44](https://i-blog.csdnimg.cn/blog_migrate/a1697c863ff123834fbe469c689a3397.png)
回过头来查看arch/arm/cpu/armv7/omap-common/u-boot-spl.lds链接脚本文件,可以看到:
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)45](https://i-blog.csdnimg.cn/blog_migrate/37f97ef611e0b079c28305cea17e155f.png)
也就是说.bss段被指向sdram存储区域,map文件则显示链接器将spl_image安排在第一个。 不知道这种安排是否是有意为之?(后来从7.00上面证明并非刻意安排,而是ld的行为) 从map看,似乎是谁离lds文件更近谁出现在map的最前面,这种安排是有些道理的,一定程度上能解释为什么spl_image在map上处于第一个。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)46](https://i-blog.csdnimg.cn/blog_migrate/1ca5700e5829f710087f1cb8e1addd90.png)
从spl_image.os的数值可以得出,下一步就是执行jump_to_image_no_args()函数。
![ti-sdk-evm-am335x-05.07 uboot分析(MLO跳转到u-boot之前)47](https://i-blog.csdnimg.cn/blog_migrate/3adf516244b136c49ebd82c460bb2a75.png)
该函数首先typedef一个新类型,该类型是入参和返回值均为void的函数指针类型,并且用这个类型定义一个变量image_entry,将spl_image.entry_point赋值给它,最后执行这个函数,从汇编的角度看,就是将spl_image.entry_point赋值给PC,下一步就是跳转到SDRAM的0x80100000执行。
--------------------------------------------------------------------------------
board_init_r End(start.s)
--------------------------------------------------------------------------------
MLO阶段结束。