Uboot15之start.S概要及头文件

1.为什么要首先分析start.S?

对于任何程序,入口函数是在链接时决定的,uboot的入口是由链接脚本决定的(入口地址也是由链接器决定的)。uboot下armv7链接脚本默认目录为arch/arm/cpu/u-boot.lds。

指定程序的链接地址有2种方法:

1)一种是在Makefile中ld的flags用-Ttext 0xc3e00000来指定;

Uboot15之start.S概要及头文件

Uboot15之start.S概要及头文件

2)第二种是在链接脚本u-boot.lds的SECTIONS开头用.=0xc3e000000来指定。

Uboot15之start.S概要及头文件

两种都可以实现相同效果。其实,这两种技巧是可以共同配合使用的,也就是说既在链接脚本中指定也在ld flags中用-Ttext来指定。两个都指定以后以-Ttext指定的为准。

uboot的最终链接起始地址就是在Makefile中用-Ttext 来指定的,具体参见2.4.5.2节,注意TEXT_BASE变量。最终来源是Makefile中配置对应的命令中,在make xxx_config时得到的。

Uboot15之start.S概要及头文件

1)在C语言中整个项目的入口就是main函数(这是C语言规定的),所以譬如说一个有10000个.c文件的项目,第一个要分析的文件就是包含了main函数的那个文件。

2)在uboot中因为有汇编阶段参与,因此不能直接找main.c。整个程序的入口取决于链接脚本中ENTRY声明的地方。ENTRY(_start)因此_start符号所在的文件就是整个程序的起始文件,_start所在处的代码就是整个程序的起始代码。

2. start.S的结构

bootloader通常stage1和stage2两步骤,u-boot也不例外。

Stage1:依赖于CPU体系结构的代码(如设备初始化代码等)通常都放在这个程序段,且可以用汇编语言来实现;

stage2:通常用C语言来实现,这样可以实现复杂的功能,而且有更好的可读性和移植性。

Stage1 :start.S代码结构

u-boot的stage1代码通常放在start.S文件中,用汇编语言写成,其主要代码部分如下:

(1) 定义入口。由于一个可执行文件必须有一个入口点,并且只能有一个全局入口,通常这个入口放在ROM(Flash)的0x0地址。因此,必须通知编译器以使其知道这个入口,该工作可通过修改链接器脚本(.lds文件)来完成。

(2) 设置异常向量(Exception Vector)。

(3) 设置CPU的速度、时钟频率及终端控制寄存器。

(4) 初始化内存控制器。

(5) 将ROM中的代码复制到RAM中。

(6) 初始化堆栈。

(7) 转到RAM中执行,该工作可使用指令ldr pc来完成。

Stage2 :C语言代码部分

./arch/arm/lib/board.c中的board_init_r()是C语言开始的函数,也是整个启动代码中C语言的主函数,同时还是整个u-boot(armboot)的主函数,该函数主要完成如下操作:

(1) 调用一系列的初始化函数。

(2) 初始化Flash设备。

(3) 初始化系统内存分配函数。

(4) 如果目标系统拥有NAND设备,则初始化NAND设备。

(5) 如果目标系统有显示设备,则初始化该类设备。

(6) 初始化相关网络设备,填写IP、MAC地址等。

(7) 进去命令循环(即整个boot的工作循环),接收用户从串口输入的命令,然后进行相应的工作。

3. start.S的头文件

#include <config.h>

#include <version.h>

#if defined(CONFIG_ENABLE_MMU)

#include <asm/proc/domain.h>

#endif

#include <regs.h>

 

#ifndef CONFIG_ENABLE_MMU

#ifndef CFG_PHY_UBOOT_BASE

#define CFG_PHY_UBOOT_BASE    CFG_UBOOT_BASE

#endif

#endif

1)#include <config.h>。config.h是在include目录下的,这个文件不是源码中本身存在的文件,而是配置过程中自动生成的文件。(详见mkconfig脚本)。这个文件的内容其实是包含了一个头文件:#include <configs/x210_sd.h>".

Uboot15之start.S概要及头文件

Uboot15之start.S概要及头文件

2)经过分析后,发现start.S中包含的第一个头文件就是:include/configs/x210_sd.h,这个文件是整个uboot移植时的配置文件。这里面是好多宏。因此这个头文件包含将include/configs/x210_sd.h文件和start.S文件关联了起来。因此之后在分析start.S文件时,主要要考虑的就是x210_sd.h文件。

3)#include <version.h>。include/version.h中包含了include/version_autogenerated.h,这个头文件就是配置过程中自动生成的。里面就一行内容:#define U_BOOT_VERSION "U-Boot 1.3.4"。这里面定义的宏U_BOOT_VERSION的值是一个字符串,字符串中的版本号信息来自于Makefile中的配置值。这个宏在程序中会被调用,在uboot启动过程中会串口打印出uboot的版本号,那个版本号信息就是从这来的。

Uboot15之start.S概要及头文件Uboot15之start.S概要及头文件

4)#include <asm/proc/domain.h>。asm目录不是uboot中的原生目录,uboot中本来是没有这个目录的。asm目录是配置时创建的一个符号链接,实际指向的是就是asm-arm(详解上一章节分析mkconfig脚本时).

Uboot15之start.S概要及头文件

5)经过分析后发现,实际文件是:include/asm-arm/proc-armv/domain.h

Uboot15之start.S概要及头文件

6)从这里可以看出之前配置时创建的符号链接的作用,如果没有这些符号链接则编译时根本通不过,因为找不到头文件。(所以uboot不能在windows的共享文件夹下配置编译,因为windows中没有符号链接)

思考:为什么start.S不直接包含asm-arm/proc-armv/domain.h,而要用asm/proc/domain.h。这样的设计主要是为了可移植性。因为如果直接包含,则start.S文件和CPU架构(和硬件)有关了,可移植性就差了。譬如我要把uboot移植到mips架构下,则start.S源代码中所有的头文件包含全部要修改。我们用了符号链接之后,则start.S中源代码不用改,只需要在具体的硬件移植时配置不同,创建的符号链接指向的不同,则可以具有可移植性。

7) <regs.h>也是在配置中生成的,在mkconfig代码中提到了regs.h的生成。其实是指向的是s5pc110.h,它定义了一些我们所要用到的一些寄存器。

Uboot15之start.S概要及头文件