一) Linux的开机流程
【step 1】 加载BIOS硬件信息,寻找启动磁盘(Boot Disk);
【step 2】 读取MBR中的内核加载程序(Kernel Loader, 一般是LILO或者GRUB),这个程序的作用就是加载存储在某个位置的操作系统内核;
【step 3】 加载操作系统核心Kernel。内核的主要工作就是检测所有的硬件设备,并为它们加载驱动程序。
驱动程序有两种,即静态驱动程序(static driver)和动态驱动程序(dynamic driver)。前者以内核镜像文件的形式存在,后者则存储在文件系统上。此时,文件系统尚未挂载到系统中,所以只有静态驱动程序能被使用来驱动硬件设备。
内核另一个任务是以只读方式挂载根文件系统。挂载根目录系统的过程请参看本文的第三部分。根文件系统必须包含如下几个目录,也就是说下面几个目录只能放在根目录下面:(1)/etc/;(2)/bin/;(3)/sbin/;(4)/lib/;(5)/dev/。如果这5个目录不在根目录下面,会导致系统启动失败。
挂载了根文件系统后,系统就能安装适当的内核模块,启用某些功能,并且能调用之前所说的动态驱动程序来驱动默写硬件设备;系统还能启动存储于根文件系统中的init服务,以便让它来接受后续的启动工作。
【step 4】 Kernel执行进程/sbin/init,并取得默认的运行级别(run level),在Red Hat中,init从/etc/inittab中获取run level。
【step 4.1 】init执行/etc/rc.d/rc.sysinit文件
这个script的主要功能是进行Linux系统环境的配置,诸如界面文字字体、时间、系统记录等。这里实现的功能比较多,期间还要加载Linux系统的一些内置功能及变量,如PATH或umask。
如:
* 设置主机名
if [ -f /etc/sysconfig/network ]; then
. /etc/sysconfig/network
fi
* 初始化硬件设备,包括定义在/etc/modprobe.conf的模块,ISA PnP的硬件设备和USB设备。
* 设置内核参数
# Configure kernel parameters
update_boot_stage RCkernelparam
sysctl -e -p /etc/sysctl.conf >/dev/null 2>&1
* 设置系统时间
* 启用置换内存空间
* 检查并挂载所有文件系统,并且将根文件系统的挂载参数设置为可读可写。
# Remount the root filesystem read-write.
update_boot_stage RCmountfs
if remount_needed ; then
action $"Remounting root filesystem in read-write mode: " mount -n -o remount,rw /
fi
* 启用软件磁盘阵列与LVM
* 初始化串行端口设备
* 清除过期的锁定文件与IPC文件
* 重新设置硬盘参数
【step 4.2】 init根据默认运行级别,调用/etc/rc.d/rc x,运行级别作为输入参数x。实际上这个script就是执行/etc/rc.d/rcx.d中的批次文件,来启动系统的各项服务;
【step 4.4】 init执行文件/etc/rc.d/rc.local
rc.local是整个启动过程中唯一一个可以修改的RC Script。如果希望在系统启动过程中执行什么命令,就可以把它们放在这里。
init服务的整个过程都定义在/etc/inittab
【step 5】 系统执行/bin/login
【step 6】 shell接管主机
二)Linux系统开机流程图
在邱世华的书《系统架构与目录解析》中,他绘制了一幅系统启动的流程图,我摘录于此,也可作为参考。

图1 Linux系统启动流程图
Initrd:由GRUB协助一并载入initrd文件,让kernel支持更多硬件。这是邱世华在书中给出的解释。对照上面文中对系统启动流程的描述,我推断Initrd主要完成下面工作:1)加载硬件设备的静态驱动程序;2)帮助内核挂载根文件系统,当然是以只读的方式。
三)根目录的建立过程
开机管理程序(GRUB)启动了操作系统,在加载kernel到内存中之后(step 3),kernel会自行在内存中建立一块叫做rootfs的区域供其本身使用(RAMDISK技术),而里面的功能都是kernel本身所提供的,也就是在编译kernel时所赋予的能力。
kernel加载完成之后,下一个initrd会加载正确的模块,并且在正确地辨认出存储设备的硬件之后,将系统分割区准确地挂载到根目录上,产生出一般使用的【/】根目录。
四) 解析initrd
参考文献:《linux操作系统之奥秘》,作者:邱世华
4.1 内核(kernel)加载initrd的过程
initrd的全称是initial ramdisk。顾名思义就是激活系统所需加载的文件系统。系统加载initrd的过程:
1) 当GRUB加载kernel时,kernel会先在内存中制造一个rootfs当做临时的空间供系统使用;
2) kernel会将initrd作为一个系统将其mount到rootfs上激活;
3) initrd将负责协助开机时加载kernel所无法提供的模块,包硬盘的驱动程序,及其他所有必须预先加载的驱动程序。
4.2 initrd的内容是什么?
initrd文件其实是一个gzip压缩过的cpio备份文件。所以将其中的真实内容呈现出阿里,需要先解压缩,再进行备份文件的还原。具体的步骤如下。
step 1: 建立一个空目录,并将initrd文件拷贝一份到目录下;
# mkdir /tmp/initrd
# cp /boot/initrd-2.6.25-14.fc9.i686.img /tmp/initrd
step 2: 将initrd的拷贝文件改名为.gz文件;
# cd /tmp/initrd
# mv initrd-2.6.25-14.fc9.i686.img initrd-2.6.25-14.fc9.i686.gz
step 3: 将其解压缩;
# gunzip initrd-2.6.25-14.fc9.i686.gz
step 4: 将备份文件还原。
# cpio -id <initrd-2.6.25-14.fc9.i686
4.3 initrd中的目录架构
执行了上面的命令之后,就可以看到initrd文件的真面目了。
[root@airhouse initrd]# ls -lF | grep -v initrd
total 7508
drwx------ 2 root root 4096 2009-10-12 10:37 bin/
drwx------ 3 root root 4096 2009-10-12 10:37 dev/
drwx------ 4 root root 4096 2009-10-12 10:37 etc/
drwx------ 2 root root 4096 2009-10-12 10:37 firmware/
-rwx------ 1 root root 2091 2009-10-12 10:37 init*
drwx------ 4 root root 4096 2009-10-12 10:37 lib/
drwx------ 2 root root 4096 2009-10-12 10:37 proc/
lrwxrwxrwx 1 root root 3 2009-10-12 10:37 sbin -> bin/
drwx------ 2 root root 4096 2009-10-12 10:37 sys/
drwx------ 2 root root 4096 2009-10-12 10:37 sysroot/
drwx------ 3 root root 4096 2009-10-12 10:37 usr/
当kernel激活并加载initrd时,并没有任何系统的目录架构,这时会先以initrd所提供的目录当做系统的暂时目录。
其中,最重要的当属文件init。kernel在访问initrd时,会以此文件按其内容依次完成,它负责所有从kernel交接给文件系统中操作系统的大小事务,从建立使用的目录到加载所有的模块都是靠这个script来完成。
initrd还有一个重要的使命,就是加载各种需要在开启操作系统之前就抓到的设备。这些设备当然可以放入kernel中,但是这样造成kernel文件变大,如果加入initrd中,kernel只需要按照init文件一步一步执行就可以加载这些设备。
4.4 initrd的init文件
initrd的所有工作是按照一个叫init的脚本文件进行的。它的主要内容如下。
#!/bin/nash #nash指令
mount -t proc /proc /proc # 挂载主要的文件系统/proc和/sys
setquiet
echo Mounting proc filesystem
echo Mounting sysfs filesystem
mount -t sysfs /sys /sys
echo Creating /dev # 建立设备文件所需的文件系统
mount -o mode=0755 -t tmpfs /dev /dev
mkdir /dev/pts
mount -t devpts -o gid=5,mode=620 /dev/pts /dev/pts
mkdir /dev/shm
mkdir /dev/mapper
echo Creating initial device nodes # 建立最初所需使用的硬件设备
mknod /dev/null c 1 3
mknod /dev/zero c 1 5
mknod /dev/systty c 4 0
mknod /dev/tty c 5 0
mknod /dev/console c 5 1
mknod /dev/ptmx c 5 2
mknod /dev/tty0 c 4 0
mknod /dev/tty1 c 4 1
... ...
mknod /dev/ttyS0 c 4 64
mknod /dev/ttyS1 c 4 65
... ...
echo Setting up hotplug.
hotplug
echo Creating block device nodes. # 加载相关模块
mkblkdevs
echo "Loading ehci-hcd module"
modprobe -q ehci-hcd
echo "Loading ohci-hcd module"
modprobe -q ohci-hcd
echo Making device-mapper control node
mkdmnod
modprobe scsi_wait_scan
rmmod scsi_wait_scan
mkblkdevs
echo Scanning logical volumes # 扫描LVM
lvm vgscan --ignorelockingfailure
echo Activating logical volumes
lvm vgchange -ay --ignorelockingfailure VolGroup00
resume /dev/VolGroup00/LogVol01
echo Creating root device.
mkrootdev -t ext3 -o defaults,ro /dev/VolGroup00/LogVol00
echo Mounting root filesystem.
mount /sysroot
echo Setting up other filesystems. # 切入实体操作系统
setuproot
loadpolicy
echo Switching to new root and running init.
switchroot
echo Booting has failed.
sleep -1
本文详细剖析了Linux的开机流程,从加载BIOS硬件信息到寻找启动磁盘,再到执行/sbin/init并取得默认运行级别。重点讲解了内核加载驱动程序、挂载根文件系统、启用内核模块和init服务的过程。同时,提到了initrd在系统启动中的作用,包括加载硬件驱动和协助挂载根文件系统。
387





