uboot启动流程分析
目录
1.uboot源码编译
首先是将uboot源码编译一次,分析需要结合编译后的文件
.config 是由make xxx_defconfig之后产生的一个副本
u-boot.lds是 arch/arm/cpu/u-boot.lds的副本
u-boot.map是u-boot.bin的内存映射文件,详细记录了固件的内存分布情况
2.确定u-boot的入口函数和入口地址
通过u-boot.lds链接文件可以知道uboot的入口点是_start
通过u-boot.map可以知道u-boot的链接起始地址是0x87800000
3. _start函数分析
_start函数在文件 arch/arm/lib/vectors.S 中有定义
其实就是一个中断向量表,和单片机的套路是一样的,第一个执行的是reset复位函数,reset 函数在 arch/arm/cpu/armv7/start.S 文件中,源码中有众多的start.s文件,但imx6ull是ARMV7架构的,所以是armv7下的start.S
reset的调用关系如下图
4.lowlevel_init函数分析
函数 lowlevel_init 在文件 arch/arm/cpu/armv7/lowlevel_init.S 中定义
规划内存,设置栈顶地址,预留出global data 的位置,最终的规划后的内存如下
此时的uboot还是在内部的ocram内存中,还没搬迁到SDRAM中运行
最后调用s_init函数,在arch/arm/cpu/armv7/mx6/soc.c中,但此函数对于imx6ull来说是一个空函数,啥事不做。
5._main函数分析
_main 函数在文件 arch/arm/lib/crt0.S 中
经过relocat_code和relocate_vetors函数此时的uboot已经是运行到外部的sdram中了
最终的内存分配图如下
初始化一系列外设,比如串口、定时器,或者打印一些消息等。
初始化 gd 的各个成员变量,uboot 会将自己重定位到 DRAM 最后面的地址区域,也就
是将自己拷贝到 DRAM 最后面的内存区域中。这么做的目的是给 Linux 腾出空间,防止 Linux
kernel 覆盖掉 uboot,将 DRAM 前面的区域完整的空出来。
6.board_init_r函数分析
定义在在文件 common/board_r.c中
7.run_main_loop函数分析
定义在在文件 common/board_r.c中
8.cmd_process分析
cmd_process执中首先会判断当前命令是否存在,不存在则报错
uboot使用宏U_BOOT_CMD来定义命令,宏 U_BOOT_CMD 定义在文件 include/command.h 中,定义如下:
U_BOOT_CMD的宏定义最终将内容封装成cmd_tbl_s结构体,cmd_tbl_s详情如下
所有的uboot命令都会通过指定域属性链接到.u_boot_list段,在链接脚本中有体现
每个命令都有一个对应的命令执行函数,比如dhcp命令,对应do_dhcp函数,具体的命令形式如下
xxx命令,对应do_xxx函数
cmd_process最终会调用cmd_tbl_s结构体中的成员变量cmd函数指针,比如执行xxx命令,最终是会调用你do_xxx函数
uboot源码的cmd文件夹下xxx.c文件对应的是xxx命令
9.bootz 启动 Linux 内核过程
在启动 Linux 内核的时候都会用到一个重要的全局变量:
images,images 在文件 cmd/bootm.c 中有如下定义:
bootm_headers_t images; /* pointers to os/initrd/fdt images */
bootm_headers_t中有几个重要的成员变量如下:
由上一小结可以知道bootz命令源文件是cmd文件夹下的bootm.c文件,文件中对用bootz的命令回调函数是do_bootz,接下来重点分析这个函数
tftp 80800000 zImage
tftp 83000000 imx6ull-14x14-emmc.dtb
bootz 80800000 – 83000000
10.总结
1、uboot开始运行在内部ram中,待初始化完sdram(imx6ull无法初始化)后搬家至sdram空间的后面位置,目的是腾出起前面的空间给linux kernel。
2、bootargs参数通过设备树传递给linux kernel。