uboot启动流程分析
Uboot的启动流程分为两个阶段,第一阶段主要是汇编语言编写,第二阶段是C语言编写,每个阶段所做的工作不同,这篇文章分析的是uboot 2010版,以tiny4412的uboot为例。
启动过程涉及的主要文件:
arch/arm/cpu/armv7/start.S
board/samsung/myboard/lowlevel_init.S
arch/arm/lib/crt0.S
arch/arm/lib/board.c
arch/samsung/myboard/myboard.c
第一阶段 uboot的入口的地址是arch/arm/cpu/armv7/start.S, 这可以从相同路径下的连接脚本u-boot.lds 中知道。 arch/arm/cpu/armv7 /start.S 平台相关,CPU工作模式设为SVC模式,关MMU,关icahce(CPU相关) board/samsung/fs4412/lowlevel_init.S 开发板相关:关看门狗,内存初始化,时钟初始化,串口初始化(board相关,初始化最基本的硬件环境)
第二阶段 arch/arm/lib/crt0.S _main 函数所在处,初始化SP,为C语言准备,代码重定位,清BSS,设置R0 R1 R2 R8相应寄存器 arch/arm/lib/board.c board_init_f 函数 ,填充GD结构体,初始化外设, main_loop()函数超循环
第一个阶段:
在这个阶段主脉络就是:部分硬件初始化—》加载完整的uboot到RAM—》跳转到第二阶段入口开始执行。
整个过程涉及两个重要的文件:start.S和lowlevel_init.S。Start.S涉及到特定硬件设备的读写寄存器操作以及特定体系结构的汇编语言;lowlevel_init.S,涉及的操作和文件名吻合,完成底层的初始化
执行上面的_start: b reset 后跳转到下面这段代码继续运行:
继续往下分析:
程序跳转到这个函数里,我们进去看看:
上面的lowlevel_init在board/samsung/myboard/lowlevel_init.S
之后回到start.S执行
上面的代码完成了gt结构体部分成员赋值
程序往下执行到relocate_code:
经过上面的操作,uboot已经把字节从SD卡拷贝到SDRAM中,并且为之后的执行准备好了各种参数,最终跳转到第二部分的入口board_init_r
从上面可以总结出:
1.Bootloader第一阶段的功能:
- 硬件设备初始化。
- 为加载Bootloader的第二阶段代码准备RAM空间。
- 设置CPU的速度、时钟频率及终端控制寄存器
- 初始化内存控制器
- 复制Bootloader的第二阶段代码到RAM空间中。
- 设置好栈。
- 跳转到第二阶段代码的C入口点。
在第一阶段进行的硬件初始化一般包括:关闭WATCHDOG、关中断、设置CPU的速度和时钟频率、RAM初始化等。这些并不都是必需的,比如S3C2410/S3C2440的开发板所使用的U-Boot中,就将CPU的速度和时钟频率的设置放在第二阶段。
甚至,将第二阶段的代码复制到RAM空间中也不是必需的,对于NOR FLASH等存储设备,完全可以在上面直接执行代码,只不过相比在RAM中执行效率大为降低。
第二阶段分析:
- 初始化本阶段要使用的硬件设备。
- 检测系统内存映射(memory map)。
- 将内核映像和根文件系统映像从FLASH上读到RAM空间中。
- 为内核设置启动参数。
- 调用内核。
C语言代码部分 arch/arm/lib/board.c中的board_init_f是C语言开始的函数也是整个启动代码中C语言的主函数,同时还是整个u-boot的主函数,该函数只要完成如下操作:
1)调用一系列的初始化函数。
2)初始化Flash设备。
3)初始化系统内存分配函数。
4)如果目标系统拥有NAND设备,则初始化NAND设备。
5)如果目标系统有显示设备,则初始化该类设备。
6)初始化相关网络设备,填写IP、MAC地址等。
7)进去命令循环(即整个boot的工作循环),接受用户从串口输入的命令,然后进行
U-Boot的启动顺序流程图: