(1)通过对链接脚本的分析可知,整个程序的入口取决于链接脚本中 ENTRY 声明的地方。在 uboot.lds 中可以看到 ENTRY(_start),因此 _start 就是整个程序的入口,而 _start 所在的文件就是整个程序的起始文件。通过搜索可知,_start 存在 start.S 中,因此 start.S 就是整个程序的起始文件。
代码:28 ~ 33 行
#include
#include
#if defined(CONFIG_ENABLE_MMU)
#include
#endif
#include
(1)#include
include/config.h 文件不是源码中自带的,而是通过配置文件 mkconfig 自动生成的。它的内容很简单,如下所示:
#include
通过分析可知,这里包含的是 include/configs/x210_sd.h 文件(这个文件是整个 uboot 移植时的配置文件,里面有很多宏)。因此分析 start.S 时,要考虑 include/configs/x210_sd.h 。
(2)#include
include/version.h 文件的内容如下所示:
#include "version_autogenerated.h"。
include/version_autogenerated.h 头文件是在编译时自动生成的,这里面只有一个宏定义,如下所示:
#define U_BOOT_VERSION "U-Boot 1.3.4"
这个宏来自于主 Makefile 的配置值,并且在程序中被调用。在 uboot 启动过程中,串口打印出的 uboot 的版本号就来源于这里。
(3)#include
include/asm 是一个软链接,在 uboot 中本来是没有的,是在配置时创建的(详情参考 mkconfig),实际指向 include/asm-arm 目录。经过以上分析可知,这里实际包含的是 include/asm-arm/proc/domain.h 文件。
(4)#include
include/regs.h 也是一个软连接,也是在配置时创建的,实际指向 include/s5pc110.h 。
(5)从这里就可以知道之前在配置时创建的符号链接的作用,如果没有这些符号链接,编译时根本通不过,因为找不到头文件。(因此uboot不能在windows的共享文件夹下配置编译的原因是windows中没有符号链接)
(6)思考:这里为什么不直接包含,而是要用符号链接的方式?
这样的设计主要是为了可移植性。因为如果直接包含,则start.S文件和CPU架构(和硬件)相关了,可移植性就差了,假如把uboot移植到mips架构下,则start.S源代码中所有的头文件包含全部要修改。但是用了符号链接之后,start.S中源代码就不需要改,只需要在移植时,根据硬件确定在符号链接的指向,这样就具有可移植性了。
代码:49 ~ 54 行
#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
.word 0x2000
.word 0x0
.word 0x0
.word 0x0
#endif
(1)从代码中可以看出:若定义了 CONFIG_EVT1 并且没有定义 CONFIG_FUSED,那么就定义 4 字节空间。
(2)在裸机部分,SD 卡启动(或 Nand 启动)启动时,需要 16 字节的校验头(mkv210image.c 就是用来计算这个校验头的),但是当时并没有详细考虑过这个问题,是因为:dnw 方式启动时不需要这 16 字节;SD 卡启动时,mkv210image.c 会给镜像加上 16 字节的校验头。
(3)这里只是在开头位置放置了 16 字节的填充占位,这里的占位只是保证了镜像头部有 16 字节,并不保证它的内容是对的,这 16 个字节的值还需要后面去重新计算和填充的。
代码:56 ~ 83 行
.globl _start
_start: b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_undefined_instruction:
.word undefined_instruction
_software_interrupt:
.word software_interrupt
_prefetch_abort:
.word prefetch_abort
_data_abort:
.word data_abort
_not_used:
.word not_used
_irq:
.word irq
_fiq:
.word fiq
_pad:
.word 0x12345678 /* now 16*4=64 */
.global _end_vect
_end_vect:
(1)异常向量表是 CPU 设计时决定的,是硬件决定的。
(2)异常向量表的所有异常都应被处理,否则程序会飞。
(3)复位异常处理的代码时:
b reset
CPU 复位后真正去执行的有效的代码是 reset 处的代码,因此符号 reset 处的代码才是真正的有意义的代码的开始地方。
代码:85 行
.balignl 16,0xdeadbeef
(1)该条指令是让当前地址按 16 字节对其,若没有对齐,用 0xdeadbeef 数字来填充,直到对齐。
(2)0xdeadbeef 没有什么特别的意义,但是内容很有意思,刚好组成了一个单词 dead beep (坏牛肉)。
(3)为什么要对齐呢?有时候是为了提高访问效率,有时候是硬件的要求。
代码:86 ~ 135 行
/*
*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************
*/
_TEXT_BASE:
.word TEXT_BASE
/*
* Below variable is very important because we use MMU in U-Boot.
* Without it, we cannot run code correctly before MMU is ON.
* by scsuh.
*/
_TEXT_PHY_BASE:
.word CFG_PHY_UBOOT_BASE
.globl _armboot_start
_armboot_start:
.word _start
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
#if defined(CONFIG_USE_IRQ)
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
(1)TEXT_BASE
第 100 行的这个 TEXT_BASE 是在 Makefile 配置阶段时的那个 TEXT_BASE,也就是链接时指定的 uboot 中的那个链接地址,它的值时 0xc3e00000 。
在源代码中和配置的 Makefile 中,很多变量是互相关联的,有些符号的值可以从 Makefile中 传递到源代码中。
(2)CFG_PHY_UBOOT_BASE
uboot 在DDR中的物理地址 —— 0x33e00000,它的定义放在 include/configs/x210_sd.h,如下所示:
#define CFG_PHY_UBOOT_BASE MEMORY_BASE_ADDRESS + 0x3e00000
(3)_armboot_start
这个会在重定位时用到
(4)_bss_start、_bss_end
用于清理 bss 段用的