五、uboot启动的几个关键知识点
如何判断第一条机器指令的位置?
链接脚本决定了内存的布局。
uboot链接脚本如下:
u-boot-2013.01/arch/arm/cpu/u-boot.lds
文件内容:
28 ENTRY(_start)
29 SECTIONS
30 {
31 . = 0x00000000;
32
uboot的入口是_start
链接地址是0x00000000
uboot如何搬运代码?
代码位于:
u-boot-2013.01/arch/arm/cpu/armv7/start.S
搬移代码如下:
ENTRY(relocate_code)
mov r4, r0 save addr_sp
mov r5, r1 save addr of gd
mov r6, r2 save addr of destination
adr r0, _start
cmp r0, r6
moveq r9, #0 no relocation. relocation offset(r9) = 0
beq relocate_done 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
详情参考第四章,第3节。
uboot中,如何判断此次开机是从断电状态开机还是从休眠状态启动的?board/samsung/fs4412/lowlevel_init.S
代码如下:
41 lowlevel_init:
54 AFTR wakeup reset
55 ldr r2, =S5P_CHECK_DIDLE
56 cmp r1, r2
57 beq exit_wakeup
58
59 LPA wakeup reset
60 ldr r2, =S5P_CHECK_LPA
61 cmp r1, r2
62 beq exit_wakeup
63
64 Sleep wakeup reset
65 ldr r2, =S5P_CHECK_SLEEP
66 cmp r1, r2
67 beq wakeup_reset
112 wakeup_reset:
113 bl system_clock_init
114 bl mem_ctrl_asm_init
115 bl tzpc_init
116
117 exit_wakeup:
118 Load return address and jump to kernel
119 ldr r0, =(EXYNOS4_POWER_BASE + INFORM0_OFFSET)
120
121 r1 = physical address of exynos4210_cpu_resume function
122 ldr r1, [r0]
123
124 Jump to kernel
125 mov pc, r1
由上可知,当手机因为各种原因进入休眠时,会将当前程序执行的上下文保护起来,并向一些pmic的寄存器中写入指定的数据,以表明此次是因为何种原因进入休眠。
而手机并没有完全断电,而是处于一个低功耗模式下,此时启动RAM仍然有数据,所以在此启动后,只需要从特殊的寄存器中读取相应的值,就可以知道之前是因为什么原因休眠,进而回复休眠之前的上下文即可。
uboot代码搬到ram之后,代码的运行地址发生了变化,如何保证程序跳转不会出错?
除了要保证uboot代码是基于地址无关的,此外.rel.dyn帮我们解决了,其实主要还是编译器帮我们做了很多工作。
位置无关码参考《15. 从0学ARM-什么是位置无关码?》
设备启动的时候,有可能直接从ram启动, 如何知道当前是从flah启动还是ram启动的?
文件:
board/samsung/fs4412/lowlevel_init.S
代码:
lowlevel_init:
85
86 * If U-boot is already running in ram, no need to relocate U-Boot.
87 * Memory controller must be configured before relocating U-Boot
88 * in ram.
89
90 ldr r0, =0x0ffffff r0 <- Mask Bits
91 bic r1, pc, r0 pc <- current addr of code
92 r1 <- unmasked bits of pc
93 ldr r2, _TEXT_BASE r2 <- original base addr in ram
94 bic r2, r2, r0 r2 <- unmasked bits of r2
95 cmp r1, r2 compare r1, r2
96 beq 1f r0 == r1 then skip sdram init
原理:RAM地址空间是:0x40000000-0xA0000000 0xA0000000-0x00000000而iROM/iRAM地址的bit:28-31均是0,所以只需要读取出执行到lowlevel_init时pc的值,判断其bit:28-31是否是0即可知道现在代码是否运行在RAM中。