Linux的核心启动流程

下面以RedHatFedoraCore5(Linux2.6.15-1.2054_FC5)为基础说说Linux的启动流程。

打开计算机电源后,第一个执行的程序是ROMBIOS,该程序根据设置选择一个引导设备,比如软盘、硬盘、光盘或者USB盘等,然后读入引导设备上的一小段程序(称为BootLoader,常见的有lilo,grub等)。

BootLoader会读入相关的引导选单并执行。一般的引导选单上会指定从哪个设备的哪个分区读入操作系统内核,给操作系统传入哪些命令行参数(cmdline)、初始的RAMDISK(initrd)等等。BootLoader将系统核心以及initrd读入内存并传递好cmdline/initrd后就结束了自己的使命,控制权转移到Linuxkernel。

我采用的BootLoader是grub,被安装在第一个SCSI盘的第一个分区上,其上的grub.conf内容如下(#后的注释是我加的,下同):

default=0

timeout=5

splashimage=(hd0,0)/grub/splash.xpm.gz

titleFedoraCore(2.6.15-1.2054_FC5)

root(hd0,0)#指定操作系统内核(Kernel)文件所在的磁盘和分区

kernel/vmlinuz-2.6.15-1.2054_FC5roroot=LABEL=/#指定操作系统的文件名称以及cmdline

initrd/initrd-2.6.15-1.2054_FC5.img#指定initrd

titleMiniLinux-USB(2.6.15-1.2054_FC5)

root(hd1,0)

kernel/boot/vmlinuz-2.6.15-1.2054_FC5roroot=/dev/ram0

initrd/boot/initrd-minilinux-usb.img

操作系统内核(Kernel)会执行各种必要的初始化如内存页表、进程表等等数据结构,初始化被编译到Kernel的内核模块以及设备驱动等等,很多初始化都需要分析cmdline以便在多个策略中选择。

接下来的启动流程分为两个分支:

1)如果BootLoader指定了initrd,则解压initrd指定的初始RAMDISK映像到/dev/ram0并挂装/dev/ram0作为根文件系统,然后执行/init。

/init的目的一般是装载最终的根文件系统所必须的文件系统内核模块,建立一些设备特别文件并挂装最终的根文件系统(如果不是/dev/ram0)。

我安装的RedHatFC5的initrd-2.6.15-1.2054_FC5.img文件是个gzip压缩过的cpio文件,在启动完成后位于/boot目录下(因为启动分区被安装在/boot目录下,参见下篇“linux的应用启动流程”一文)。我们可以执行下述命令提取其内容

mkdir-pxxx

cdxxx

gunzip-c/boot/initrd-2.6.15-1.2054_FC5.img|cpio-idv

我们可以看到下面有很多目录和文件:

bin/dev/etc/init*lib/proc/sbin@sys/sysroot/

./bin:

insmod*modprobe@nash*

./dev:

consolenullram@ram1systtytty0tty10tty12tty3tty5tty7tty9ttyS1ttyS3

mapper/ptmxram0rtcttytty1tty11tty2tty4tty6tty8ttyS0ttyS2zero

./dev/mapper:

./etc:

./lib:

BusLogic.koext3.kojbd.koscsi_mod.kosd_mod.ko

./proc:

./sys:

./sysroot:

其中/init内容如下:

#!/bin/nash#由/bin/nash解释执行

mount-tproc/proc/proc#挂装proc文件系统

setquiet#安静模式

echoMountingprocfilesystem

echoMountingsysfsfilesystem

mount-tsysfs/sys/sys#挂装sysfs文件系统

echoCreating/dev

mount-omode=0755-ttmpfs/dev/dev

mkdir/dev/pts

mount-tdevpts-ogid=5,mode=620/dev/pts/dev/pts

mkdir/dev/shm

mkdir/dev/mapper

echoCreatinginitialdevicenodes

mknod/dev/nullc13

mknod/dev/zeroc15

mknod/dev/systtyc40

mknod/dev/ttyc50

mknod/dev/consolec51

mknod/dev/ptmxc52

mknod/dev/rtcc10135

mknod/dev/tty0c40

mknod/dev/tty1c41

mknod/dev/tty2c42

mknod/dev/tty3c43

mknod/dev/tty4c44

mknod/dev/tty5c45

mknod/dev/tty6c46

mknod/dev/tty7c47

mknod/dev/tty8c48

mknod/dev/tty9c49

mknod/dev/tty10c410

mknod/dev/tty11c411

mknod/dev/tty12c412

mknod/dev/ttyS0c464

mknod/dev/ttyS1c465

mknod/dev/ttyS2c466

mknod/dev/ttyS3c467#以上创建必要的设备特别文件

echoSettinguphotplug.

hotplug#设置可以热插拔的设备插拔时的处理程序

echoCreatingblockdevicenodes.

mkblkdevs#利用sysfs文件系统自动创建当前发现的块设备的特别文件,关于sysfs将是另一篇文章的内容了

echo"Loadingjbd.komodule"

insmod/lib/jbd.ko

echo"Loadingext3.komodule"

insmod/lib/ext3.ko

echo"Loadingscsi_mod.komodule"

insmod/lib/scsi_mod.ko

echo"Loadingsd_mod.komodule"

insmod/lib/sd_mod.ko

echo"LoadingBusLogic.komodule"

insmod/lib/BusLogic.ko#前面几个insmod装载接下来挂装最终的根文件系统所必需的驱动程序模块

mkblkdevs#创建刚刚这些驱动程序发现并注册到sysfs文件系统中的块设备的特别文件

echoCreatingrootdevice.

mkrootdev-text3-odefaults,ro/dev/root#分析kernelcmdline寻找根文件设备并创建一个特别文件指向该设备(如果是以“LABEL=”开始则自动寻找分区表上对应该LABEL的分区)并加入到/etc/fstab中

echoMountingrootfilesystem.

mount/sysroot#将最终的根文件系统临时挂装到/sysroot下

echoSettingupotherfilesystems.

setuproot#设置proc,sys等文件系统到/sysroot下

echoSwitchingtonewrootandrunninginit.

switchroot#将/sysroot切换为最终的根文件系统,并执行其上的/init,见后

2)如果BootLoader没有指定initrd,直接挂装cmdline上指定的root设备作为根文件系统,接下来按照下面的顺序寻找init程序并建立第一个进程:

run_init_process("/sbin/init");//找到就建立第一个进程(pid=0),不会返回了,下面三行同此

run_init_process("/etc/init");

run_init_process("/bin/init");

run_init_process("/bin/sh");

panic("Noinitfound.Trypassinginit=optiontokernel.");//寻找不到,打印错误信息,系统挂起

不管是哪个分支,到此为止,核心启动流程结束,后面由最终的根文件系统上的init控制转入应用启动流程,这个待下篇文章再说吧。