ARM Linux启动总体过程 Bootloader---->>Kernel---->>rootfs.

Bootloader
        一般的SOC中一般会有一块SDRAM(又叫垫脚石),当SOC上电时,SOC中固化的代码会根据启动方式从NAND,eMMC等不同存储上,加载Bootloader到SDRAM,进而执行。也就是说SOC上电后首先运行的是我们的Bootloader(如 u-boot、vivi)。(刨去SOC中固化好的代码)
   
        那Bootloader又要做什么工作,毫无疑问他的最终目的就是为了加载内核,也就是说bootloader的一切工作都是为运行内核做准备的。
         那具体做哪些工作呢?(以u-boot为例)那首先得找到u-boot的入口,由lds文件可以看出,入口就在start.S文件。做的事情比较多,但是大体上就是设置中断向量表、设置CPU、进行一系列的初始化(RAM、串口、nand flash、c运行环境等)等等,代码流程都比较清楚,就不多说了。最后跳到了Kernel。

Kernel

   先看一下kernel的组成结构:


可以看到,当内核源文件编译链接成 vmlinux 文件以后还进行了几个模块的编译和链接。其中

(1)vmlinux 是ELF格式的object文件,这种文件只是各个源代码经过连接以后的得到的文件,并不能在arm平台上运行。

(2)经过objcopy这个工具转换以后,得到了二进制格式文件Image,Image文件相比于vmlinux 文件,除了格式不同以外,还被去除了许多注释和调试的信息。

(3)Image文件经过压缩以后得到了piggy.gz ,这个文件仅仅是Image的压缩版,并无其他不同。

(4)接着编译生成另外几个模块文件misc.o、big_endian.o、head.o、head-xscale.o,这几个文件组成一个叫 bootstrap loader 的组件,又叫引导程序。编译生成 piggy.o 文件。

(5)最后piggy.o文件和bootstrap loader 组成一个bootable kernel Image 文件(可启动文件)。

那kernel的启动流程就比较清晰了,看图更清晰:


从上图可以看出,系统一上电就开始执行bootloader。当bootloader 执行完以后,把控制权交给了引导程序的head.o 文件里的start 标号处,当引导程序完成引导工作以后就将控制权转给真正的内核的head.o 文件里的start 标号处。这里就是内核的入口点,最后内核的head.o将控制交给main.o 的start_kernel 函数。这样,通过查看相应的代码就可以知道这些代码到底完成了哪些工作。在这里我们可以找到相应的代码,分析一下,看它们到底完成哪些事。下面是我的分析结果:

引导程序:

head.o从bootloader接过控制权,并完成如下任务:

  1. 使能 I/D caches ,关闭中断 , 建立C运行环境(即设置堆栈)由 head.o 和head-xscal.o 完成
  2. 解压缩并重定位代码 ,由misc.o 完成
  3. 其他硬件相关的设置,如big.endian.o 为cpu设置大端模式

内核入口点:从引导程序接过控制权,完成如下任务

  1. 检查有效的cpu 和cpu的信息
  2. 创建初始化页表入口
  3. 使能MMU
  4. 检测错误并报告
  5. 跳转到内核本身 main.c 文件里的 start_kernel()函数

内核启动:

从 kernel 的head.o接过控制权,开始内核的启动,在这里完成内核的初始化,如内核各个子系统的初始化。