Uboot28之start.S汇编语言结束
skip_hw_init:
/* Set up the stack */
再次设置栈
1)第三次设置栈。这次设置栈还是在DDR中,之前虽然已经在DDR中设置过一次栈了,但是本次设置栈的目的是将栈放在比较合适(安全,紧凑而不浪费内存)的地方。
2)我们实际将栈设置在uboot起始地址上方2MB处,这样安全的栈空间是:2MB-uboot大小-0x1000=1.8MB左右。这个空间既没有太浪费内存,又足够安全。
stack_setup:
#if defined(CONFIG_MEMORY_UPPER_CODE)
ldr sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0x1000)
#else
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot C3E00000*/
sub r0, r0, #CFG_MALLOC_LEN /* malloc area 912K */
#define CFG_MALLOC_LEN (CFG_ENV_SIZE + 896*1024)
#define CFG_ENV_SIZE 0x4000 /* Total Size of Environment Sector */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#define CFG_GBL_DATA_SIZE 128 /* size in bytes reserved for initial data */
#if defined(CONFIG_USE_IRQ)
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
#endif
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
注意表示bss段的开头和结尾地址的符号是从链接脚本u-boot.lds得来的。
clbss_l:
str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
ldr pc, _start_armboot
_start_armboot:
.word start_armboot
ldr pc, _start_armboot
1)start_armboot是uboot/lib_arm/board.c中,这是一个C语言实现的函数。这个函数就是uboot的第二阶段。这句代码的作用就是将uboot第二阶段执行的函数的地址传给pc,实际上就是使用一个远跳转直接跳转到DDR中的第二阶段开始地址处。
2)远跳转的含义就是这句话加载的地址和当前运行地址无关,而和链接地址有关。因此这个远跳转可以实现从SRAM中的第一阶段跳转到DDR中的第二阶段。
3)这里这个远跳转就是uboot第一阶段和第二阶段的分界线。
#if defined(CONFIG_ENABLE_MMU)
_mmu_table_base:
.word mmu_table
#endif
第一阶段:主要是SOC内部的初始化,板级的初始化比较少,所以移植的修改量比较小。此阶段由汇编语言编写,代码主体分布在start.S和lowlevel_init.S中。
其中start.S作为主干,其主要流程为:
注:加粗的比较重要,和板级有点关系
1. 填充16字节的校验位
2. 设置异常向量表
3. 设置cpu为SVC模式
4. 禁用cach和mmu
5. 判断启动介质
6. 在SRAM中设置栈
7. 跳入 lowlevel_init.S
关看门狗
设置供电锁存
判断当前执行位置
初始化时钟
初始化DDR
初始化串口(打印'OK')
8. 再次供电锁存
9. 在DDR中设置栈
10. 通过引脚判断启动介质
11. 跳到movi.c
重定位
12. 跳入 lowlevel_init.S设置虚拟地址映射
13. 在DDR中合理的地方设置栈
14. 清bss段
15. 跳入board.c,到DDR中执行程序