【版权申明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
uboot启动的通用流程
1. arch\arm\cpu\armv7\xxxxxx\start.S
由u-boot-2016.11\arch\arm\cpu\armv7\xxxxxx\u-boot.lds的ENTRY(_start)可知, uboot的入口为_start.
.globl _start
_start:
1. 设置CPU为SVC模式
2. 关闭中断/MMU/Cache
3. 关闭看门狗
4. 初始化内存/串口
5. 设置栈
6. 清BSS
7. 代码重定位
8. 跳转执行C代码, 我这里是start_armboot
(然后我就迷路了, 找不到具体执行流程, 估计是uboot被IC厂改动过, 跑着他们定制的初始化流程)
2. u-boot-2016.11\arch\arm\lib\crt0.S
尽管我上面迷路了, 但是根据uboot的通用流程可知, uboot最终会进入到_main()函数中, 标志着uboot的第二个阶段的开始!!!
ENTRY(_main)
// Set up initial C runtime environment and call board_init_f(0).
.......
board_init_f
board_init_r
ENDPROC(_main)
# u-boot-2016.11\common\board_f.c
board_init_f(ulong boot_flags):
zero_global_data(); // Clear global data
initcall_run_list(init_sequence_f); // 遍历函数指针数组init_sequence中的每一个成员, 初始化了很多东西, 没细看.
# u-boot-2016.11\common\board_r.c
board_init_r(gd_t *new_gd, ulong dest_addr):
打开cache
中断初始化
使能中断
网卡初始化, 函数的实现在net/eth.c, 会回调板级xxx.c中的board_eth_init()
...
run_main_loop
static int run_main_loop(void)
/* main_loop() can return to retry autoboot, if so just run it again */
for (;;)
main_loop(); // 执行超循环, 主要功能是处理环境变量, 解析命令
3. u-boot-2016.11\common\main.c
上面的第二节最后执行到了main_loop(), main_loop()实现了循环检测输入的命令并执行, 其中的一个环境变量bootdelay(延时时间)的设置决定了是否启动内核,如果在规定的时间内uboot没有接收到按键, 则会去引导内核.
bootloader要想启动内核, 可以直接跳到内核的第一个指令处, 即内核的起始地址, 这样便可以完成内核的启动工作. 但是要想启动内核还需要满足下面的一些条件, 这些条件在Linux内核文档"/Documentation/kernel-parameters.txt"中有说明.
void main_loop(void)
autoboot_command(s); // s是字符串, 存储着需要运行的命令集.
1. abortboot(stored_bootdelay) // 没有被uboot的按键输入打断时
run_command_list(s, -1, 0); // 执行s中存储的命令, 其中包含着启动内核的命令.
2. abortboot(stored_bootdelay) // 被uboot的按键输入打断时
... // 进入持续解析输入命令模式.