预备知识
可执行文件由许多链接在一起的对象文件组成。对象文件有许多节,如文本、数据、init 数据、bss等。这些对象文件都是由一个称为 链接器脚本(*lds)的文件链接并装入的。这个链接器脚本的功能是将输入对象文件的各节映射到输出文件中;换句话说,它将所有输入对象文件都链接到单一的可执行文件中,将该可执行文件的各节装入到指定地址处。 因此在分析u-boot代码时,首先应关注的是u-boot.lds文件。
路径: $(U-BOOT_SRC_ROOT)/board/$(BOARD_NAME)
U-Boot启动过程分析
U-Boot的启动过程可以分为两个阶段,两个阶段分别完成如下功能:
(1)第一阶段的功能
Ø 硬件设备初始化
Ø 加载U-Boot第二阶段代码到RAM空间
Ø 设置好栈
Ø 跳转到第二阶段代码入口
(2)第二阶段的功能
Ø 初始化本阶段使用的硬件设备
Ø 检测系统内存映射
Ø 将内核从Flash读取到RAM中
Ø 为内核设置启动参数
第一阶段对应的文件是start.S和lowlevel_init.S。
U-Boot启动第一阶段流程如下:
首先分析u-boot.lds文件
/*
* OUTPUT_FORMAT(default, big, little),在链接的时候,如果使用了-EB的命令行参数,则使用这里的big
* 参数指定的字节序,如果使用了-EL;的命令行参数,则使用这里的little参数指定的字节序,如果没有使用
* 任何命令行参数,则使用这里的default参数指定的字节序。
* 由$(SRC_ROOT)/board/samsung/smdk6410/u-boot.lds中的定义可见,不管在链接的时候使用了何种命令行参数,
* 输出的目标文件都是使用elf32-littlearm方式的字节序。
*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
/*以上语句是指定输出可执行文件是elf格式,32位ARM指令,小端 */
/*指定输出可执行文件的平台为ARM*/
OUTPUT_ARCH(arm)
/*指定输出可执行文件的起始代码段为_start.*/
ENTRY(_start)
SECTIONS
{
/*定位当前地址为0x0地址*/
. = 0x00000000;
/*指定代码以4字节对齐*/
. = ALIGN(4);
/*指定代码段 */
.text :
{
cpu/s3c64xx/start.o (.text) /*代码的第一个代码部分*/
cpu/s3c64xx/s3c6410/cpu_init.o (.text)
cpu/s3c64xx/onenand_cp.o (.text)
cpu/s3c64xx/nand_cp.o (.text)
cpu/s3c64xx/movi.o (.text)
*(.text)
lib_arm/div0.o
}
. = ALIGN(4);
.rodata : { *(.rodata) } /*指定只读数据段 */
. = ALIGN(4);
.data : { *(.data) } /*指定读写数据段*/
. = ALIGN(4);
.got : { *(.got) } /*指定got段, got段式是uboot自定义的一个段, 非标准段*/
__u_boot_cmd_start = .; /*把__u_boot_cmd_start赋值为当前位置, 即起始位置*/
.u_boot_cmd : { *(.u_boot_cmd) } /*指定u_boot_cmd段, uboot把所有的uboot命令放在该段.*/
__u_boot_cmd_end = .; /*把__u_boot_cmd_end赋值为当前位置,即结束位置*/
. = ALIGN(4);
.mmudata : { *(.mmudata) }
. = ALIGN(4);
__bss_start = .; /*把__bss_start赋值为当前位置,即bss段的开始位置*/
.bss : { *(.bss) } /*指定bss段 */
_end = .; /*把_end赋值为当前位置,即bss段的结束位置 */
}
由u-boot.lds文件可知:第一个链接的是start.o文件,因此u-boot.bin的入口代码在start.o中,其源代码为start.S,u-boot.bin执行的入口点为ENTRY(_start)。