Linux启动过程(尚未完成)

不当之处,尽请大家斧正。


一.  将内核映像加载到内存

1) pc / grub环境

a)bios初始化结束后,根据用户的配置,选择第一个启动设备,例如第一块硬盘,将其0扇区(即MBR)的内容(512字节)拷贝到内存中,然后执行其中的内容。

b)这512字节的内容,负责将grub加载到内容中,将控制权交给grub。

c) grub根据配置(/boot/grub/grub.conf),将bzImage(例如/boot/vmlinuz-2.6.18-194.el5)加载到内核中,

同时将initrd文件(例如/boot/initrd-2.6.18-194.el5.img)也加载到内核中。

然后grub执行bzImage起始处的内容。

2) arm / u-boot环境

a)cpu根据硬件的配置,按一定的顺序。依次尝试从sd/tf card、nand flash、spi flash等设备的起始位置(即boot sector)加载前4K字节的数据到内存中执行。

b)这前4K字节的内容,负责将u-boot加载到内容中,将控制权交给u-boot。

c) u-boot根据配置(环境变量),将zImage加载到内核中(如果是nand/nor flash,一般很简单,zImage就在flash的某个区间中,u-boot不需要支持文件系统的访问)。

同时将initrd文件也加载到内核中(同样,如果是nand/nor flash,也就简单了,initrd文件就在flash的某个区间中,u-boot不需要支持文件系统的访问)。

然后u-boot执行zImage起始处的内容。


二、内核映像究竟是什么

上一步,已经进行到boot loader执行内核映像的环节了。

zImage或bzImage,就是所谓的内核映像。

他是通过如下步骤生成的:


1) 编译得到原始的内核目标文件kernel.o

这个文件的文件名,在不同架构的makefile中叫法可能不尽相同。我们就叫他 kernel.o 好了。

这是一个elf格式的文件。

具体文件名,参见arch\xxx\boot\compressed\Makefile

另外,我们下文中所使用的文件名,也可能与makefile中的命名不一致。

不是不想一致,而是不同架构makefile中的命名确实不尽相同。

因此,我们这里为了表达的方便,就重新统一命名啦。


2)  用objcopy工具给 kernel.o 减肥,得到kernel.bin

经过objcopy处理后,得到只剩下内核代码与数据的文件kernel.bin。

注意,kernel.bin已经不是elf文件了。


3)  用gzip压缩 kernel.bin 得到 piggy.gz


4)  创建piggy.o用于包含piggy.gz文件的全部数据

piggy.o是一个elf文件,他内部包含了piggy.gz文件的全部数据。

piggy.o的目的,就是为了将piggy.gz作为数据与内核映像的其他部分进行链接。

在arm下,通过对arch\xxx\boot\compressed\piggy.S文件的编译,实现了piggy.o的创建。

在i386下,通过arch\i386\boot\compressed\vmlinux.scr链接脚本以及

arch\i386\boot\compressed\Makefile中类似如下的依赖关系,直接链接得到了piggy.o

$(obj)/piggy.o: $(src)/vmlinux.scr $(obj)/piggy.gz 


5)  将piggy.o及其他东东链接成vmlinux

将head.o、misc.o、piggy.o 链接成vmlinux。

对于arm来说,除了head.o、misc.o,可能还会将其他一些用到的东东链接进去。


6)  生成最终的内核映像文件

a) 对于arm来说,步骤如下:

用objcopy工具给 vmlinux 减肥,得到zImage

 vmlinux是elf文件,经过objcopy处理后,得到只剩下代码与数据的文件zImage。

注意,zImage已经不是elf文件了。


三、内核映像的执行

a) 对arm而言

zImage起始处的内容就是head.o中的代码。

head.o(对应arch\arm\boot\compressed\head.S)中包含一些初始化代码,进行一些系统级的处理工作。

然后head.o调用misc.o(对应arch\arm\boot\compressed\misc.c)中的解压函数,将原始内核kernel.bin解压出来。

解压完成后,就跳转到kernel.bin的起始处运行。

kernel.bin的起始处的内容,就是arch\arm\kernel\head.S。

这是一个汇编代码写的文件,ENTRY(stext)是这段代码的入口。

这段代码进行一系列的初始化工作,最后调用start_kernel函数(位于init\main.c中),进入了C代码的世界。



你可能感兴趣的:(Linux启动过程(尚未完成))