u-boot 启动过程
(一)ctags 安装
ubuntu下的代码追踪工具:ctags
windows下的代码追踪工具:Source Insight
(1)安装ctags,在ubuntu中默认已经安装好ctags.
sudo apt-get install ctags
(2)进入到要追踪的源码的顶层目录下,
ctags -R:在源码的顶层目录下生成tags文件, -R:递归
执行以下命令:
vi -t 想追的内容
(3)只能在tags所在目录下,vim/vi + 绝对路径,打开u-boot下的源码文件。
vi 从源码顶层开始的路径/xxx.c
vi arch/arm/cpu/slsiap/s5p6818/start.S
注意:只能一步到位使用:vim + 绝对路径,打开想要追踪的文件;
cd /ls /vim:一步一步打开错误。
eg错误方式:cd arch/arm/cpu/slsiap/s5p6818/ -> vi start.S
(4)代码追踪
- 将光标放到要追踪的函数处,按ctrl + ] 进入追踪的界面
- 选择位置序号,进入追踪的代码定义处
ctrl + t : 返回上一级
注意:
(1)如果函数的调用和定义都在当前文件,则直接命令行搜索:/要追踪的内容
(2)如果不在当前文件中定义,选中要追踪的内容,ctrl + ]使用ctags工具进行追踪
(二)uboot 启动过程
(1)链接脚本u-boot.lds
uboot启动过程中做的工作,可以通过追踪u-boot代码的执行过程。即找到ubootpak.bin文件执行的第一条指令。需要查看链接脚本文件,u-boot.lds。
u-boot.lds :指导编译器链接编译目标文件[.o]生成可执行文件[.elf]时,代码在内存空间中的排布。
u-boot.lds脚本源码(部分):
2 OUTPUT_ARCH(arm)
3 ENTRY(_stext) //指定程序入口,在start.S中可看到地址符号_stext:
4 SECTIONS //整个链接脚本
5 {
6 . = 0x00000000;//当前地址
7 . = ALIGN(4); //申请2^4 = 16字节的占位内存空间
8 .text ://文本段
9 {
10 *(.__image_copy_start)//当前字段是一个变量:表示可以申请的占位内存空间
11 arch/arm/cpu/slsiap/s5p6818/start.o (.text*)//程序入口执行的第一个文件:start.S
12 arch/arm/cpu/slsiap/s5p6818/vectors.o (.text*)//第二个是中断异常向量表vectors.S
13 *(.text*)//其他文件,根据编译器自动排布
14 }
- __image_copy_start代码追踪查看:
char __image_copy_start[0] :占用0字节内存
在arch/arm/lib/sections.c中定义:
22 char __bss_start[0] __attribute__((section(".__bss_start")));
23 char __bss_end[0] __attribute__((section(".__bss_end")));
24 char __image_copy_start[0] __attribute__((section(".__image_copy_start")));
25 char __image_copy_end[0] __attribute__((section(".__image_copy_end")));
26 char __rel_dyn_start[0] __attribute__((section(".__rel_dyn_start")));
27 char __rel_dyn_end[0] __attribute__((section(".__rel_dyn_end")));
28 char _end[0] __attribute__((section(".__end")));
~
(2)start.S分析
打开 vi arch/arm/cpu/slsiap/s5p6818/start.S:
2 * armboot - Startup Code for NXPxxxx/ARM Cortex CPU-core//启动代码-ARM
14 * Exception vectors as described in ARM reference manuals
15 *
16 * replace arm/lib/vectors.S
20 .globl _stext
21 _stext: //程序入口,以下8个指令作用:构建异常向量表,各异常顺序不可改变
22 b reset//执行的第一个指令:跳转到reset异常下 -》搜索/reset
23 ldr pc, _undefined_instruction
24 ldr pc, _software_interrupt
25 ldr pc, _prefetch_abort
26 ldr pc, _data_abort
27 ldr pc, _not_used
28 ldr pc, _irq
29 ldr pc, _fiq
30
31 _undefined_instruction: .word undefined_instruction
32 _software_interrupt: .word software_interrupt
33 _prefetch_abort: .word prefetch_abort
34 _data_abort: .word data_abort
35 _not_used: .word not_used
36 _irq: .word irq
37 _fiq: .word fiq
38
39 .balignl 16,0xdeadbeef
40
~
(3)Reset handler 分析
76 .globl reset
77
78 reset:
79 bl save_boot_params 跳转到save_boot_params:保存启动参数
80 /*
81 * set the cpu to SVC32 mode
82 */ 设置SVC工作模式
83 mrs r0, cpsr 把cpsr中的值保存到r0中
84 bic r0, r0, #0x1f 清除r0后5位并保存到r0
85 orr r0, r0, #0xd3
86 msr cpsr,r0 切换到SVC,确保进入SVC工作模式
87
88 /* disable watchdog*/ 禁止看门狗:看门狗上电时默认状态是启动的,禁止WTD防止启动不起来
89 ldr r0, =0xC0019000
90 mov r1, #0
91 str r1, [r0]
94 #ifndef CONFIG_SKIP_LOWLEVEL_INIT 因为没有定义此变量,需执行下面两个指令
95 bl cpu_init_cp15 完成:
96 bl cpu_init_crit
97 #endif
100 relocate_to_text: u-boot代码自搬移到内存存放文本的位置
101 /*
102 * relocate(搬移) u-boot code on memory to text base
103 * for nexell arm core (add by jhkim)
104 */
105 adr r0, _stext /* r0 <- current position of code */
106 ldr r1, TEXT_BASE /* test if we run from flash or RAM */
107 cmp r0, r1 /* don't reloc during debug */
108 beq clear_bss
109
110 ldr r2, _bss_start_ofs
111 add r2, r0, r2 /* r2 <- source end address */
112
113 copy_loop_text:
114 ldmia r0!, {r3-r10} /* copy from source address [r0] */
115 stmia r1!, {r3-r10} /* copy to target address [r1] */
116 cmp r0, r2 /* until source end addreee [r2] */
117 ble copy_loop_text
118
119 ldr r1, TEXT_BASE /* restart at text base */
120 mov pc, r1
122 clear_bss: //清除bss段
123 #ifdef CONFIG_MMU_ENABLE
124 bl mmu_turn_on
125 #endif
126 ldr r0, _bss_start_ofs
127 ldr r1, _bss_end_ofs
128 ldr r4, TEXT_BASE /* text addr */
129 add r0, r0, r4
130 add r1, r1, r4
131 mov r2, #0x00000000 /* clear */
...
144 bl board_init_f
...
160 ldr pc, =board_init_r 自搬移/* this is auto-relocated! */
...
162 #else /* CONFIG_RELOC_TO_TEXT_BASE */
163
164 bl _main 跳转到主函数
165 #endif
~
(1)bl cpu_init_cp15
禁止MMU和cache,设置协处理器
207 /* cpu_init_cp15
208 *
209 * Setup CP15 registers (cache, MMU, TLBs). The I-cache is turned on unless
211 *设置CP15寄存器(缓存,MMU, TLBs)。除非定义了CONFIG_SYS_ICACHE_OFF打开I-cache。
212 *************************************************************************/
213 ENTRY(cpu_init_cp15)
214 /*
215 * Invalidate L1 I/D
216 */
217 mov r0, #0 @ set up for MCR 设置协处理器:忽略TLBs、icache、BP组
218 mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
219 mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
220 mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array
221 #ifndef CONFIG_MACH_S5P6818
222 mcr p15, 0, r0, c7, c10, 4 @ DSB
223 mcr p15, 0, r0, c7, c5, 4 @ ISB
224 #endif
225
226 /*
227 * disable MMU stuff and caches
228 */禁止MMU和cache:MMU内存管理单元,进行物理内存和虚拟内存映射;
本阶段使用的都是物理内存,所以需要禁止mmu。
229 mrc p15, 0, r0, c1, c0, 0
230 bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
231 bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
232 orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
233 orr r0, r0, #0x00000800 @ set bit 11 (Z---) BTB
234 #ifdef CONFIG_SYS_ICACHE_OFF
235 bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache
236 #else
237 orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache
238 #endif
239 mcr p15, 0, r0, c1, c0, 0 返回到跳转前的位置处
240 mov pc, lr @ back to my caller
241 ENDPROC(cpu_init_cp15)
(2)bl cpu_init_crit
244 /*************************************************************************
245 *
246 * CPU_init_critical registers CPU临界资源初始化寄存器
247 *
248 * setup important registers
249 * setup memory timing
250 *
251 *************************************************************************/
252 ENTRY(cpu_init_crit)
253 /*
254 * Jump to board specific initialization...
255 * The Mask ROM will have already initialized
256 * basic memory. Go here to bump up clock rate and handle
257 * wake up conditions.
258 */
259 b lowlevel_init @ go setup pll,mux,memory
260 ENDPROC(cpu_init_crit)
261 #endif
b lowlevel_init
11 lowlevel_init: 低电平初始化
12
13 /* get cpu id */ 获取cpu的id
14 mrc p15, 0, r0, c0, c0, 5 @ Read CPU ID register
15 ands r0, r0, #0x03 @ Mask off, leaving the CPU ID field
16 mov r1, #0xF @ Move 0xF (represents all four ways) into r1
17
18 /* join SMP */
19 mrc p15, 0, r0, c1, c0, 1 @ Read ACTLR
20 mov r1, r0
21 orr r0, r0, #0x040 @ Set bit 6
22 cmp r0, r1
23 mcrne p15, 0, r0, c1, c0, 1 @ Write ACTLR
24
25 /* enable maintenance broadcast */使能保持广播设置
26 mrc p15, 0, r0, c1, c0, 1 @ Read Aux Ctrl register
27 mov r1, r0
28 orr r0, r0, #0x01 @ Set the FW bit (bit 0)
29 cmp r0, r1
30 mcrne p15, 0, r0, c1, c0, 1 @ Write Aux Ctrl register
31
32 mov pc, lr @ back to caller 返回调用处
(3)board_init_f
追踪代码:对bd_t/gd_t等底板信息的结构体变量,进行初始化赋值操作。
263 void board_init_f(ulong bootflag)
264 {
265 bd_t *bd;
266 init_fnc_t **init_fnc_ptr;
267 gd_t *id;
268 ulong addr, addr_sp;
...
}
(4)board_init_r
board_init_r函数:完成了大部分串口,内存,flash,cache等硬件的初始化
509 void board_init_r(gd_t *id, ulong dest_addr)
510 {
511 ulong malloc_start;
512 #if !defined(CONFIG_SYS_NO_FLASH)
513 ulong flash_size;
514 #endif
521 /* Enable caches */使能cache
522 enable_caches();
524 debug("monitor flash len: %08lX\n", monitor_flash_len);
525 board_init(); /* Setup chipselects */ 底板初始化
533 set_cpu_clk_info(); /* Setup clock information */
615 /* initialize environment */初始化环境变量
616 if (should_load_env())
617 env_relocate();
618 else
619 set_default_env(NULL);
625 stdio_init(); /* get the devices list going. */ 设备启动列表
626
627 jumptable_init();
628
629 #if defined(CONFIG_API)
630 /* Initialize API */ 初始化API接口
631 api_init();
632 #endif
633
634 console_init_r(); /* fully init console as a device */ 控制台初始化
635
636 #ifdef CONFIG_PMIC_REG_DUMP
637 power_init_board(); 底板上电初始化
638 #endif
...
708
709 /* main_loop() can return to retry autoboot, if so just run it again. */
main_loop()可以返回重复自动引导u-boot启动,如果是这样的话,只需再次运行它
710 for (;;) {
711 main_loop();
712 }
713 除了引导之外,没有方法跳出命令循环
714 /* NOTREACHED - no way out of command loop except booting */
715 }
(三)u-boot 启动总结
uboot启动阶段,主要干了哪些事?
-
阶段1:汇编阶段
1》构建异常向量表
2》ARM切换到SVC工作模式,关闭看门狗WTD,禁止中断
3》关闭MMU和cache
4》一些串口、定时器、环境变量、I2C/SPI总线等的初始化
5》完成u-boot代码的自搬移,清除bss段 -
阶段2:c语言阶段
1》完成对bd和gd结构体的初始化
2》完成大部分硬件的初始化:串口,网卡,flash,使能中断等等
3》根据bootdelay倒计时是否为0,切换uboot进入自启动模式还是交互模式
4》执行u-boot环境变量bootcmd中的命令,并将bootargs参数传递给内核