每当你按下开机电源键的时候,总是怀着一颗虔诚的心,抱着求神拜佛的念头,祈求机器顺利开机,不要出幺蛾子;每当你看到屏幕上输出的一行又一行的信息,绿的OK,红的failed,迷茫的眼神穿透了显示器;这一切都是因为你不懂系统的启动过程及初始化流程。在这里,力图将Linux系统的启动过程及初始化描述清楚,阐述好背后的原理。在撰写本文的时候,必定会因为个人对知识理解的偏差,知识面的狭窄也限制了博文内容,因此,希望小友们能够提出宝贵意见。

Linux系统的启动及初始化是Linux学习过程中非常重要的一个点,只有洞悉系统启动过程、初始化了哪些内容,才能对Linux有更加深入的了解。本文主要描述Linux系统从电脑开机到初始化完成整个过程,包括cpu加电自检、bios寻找启动项、bootloader加载系统内核、系统启动并初始化等等。



wKiom1MVujWhQ5zwAAGLjcuWooc504.jpg





一、“人生”第一步,加电自检

POST(Power on self test)。电脑开机通上电源后第一件事便是给cpu加载电源,cpu需要对硬件设备等外设进行检测,以便于启动系统。然后cpu本身是不存储任何信息的,所以,cpu根据固定在内部的指向信息,从COMS中加载BIOS里存储的内容,对各个硬件如硬盘、PCI设备、内存等进行检测。如果出现错误,如内存没有插好,电脑会发出警报,无法启动;(这一步也可以算作是BIOS的工作)

二、BIOS的主要任务

BIOS中的信息被加载到cpu中,cpu负责将这些程序运行起来,一是进行自检,对周边的硬件设备进行检测,确保系统启动的硬件环境;二是,在自检完成之后,由于电脑中可能存在多个能够用于启动系统的驱动器,所以,需要根据BIOS中启动顺序(boot sequence)的设定,找到启动系统的驱动器。例如我们的硬盘。BIOS会去读取硬盘上的第一个扇区(512K):MBR(master boot recoder)。至于MBR中是什么内容,怎样来启动系统,BIOS并不关心。它只负责读取该扇区上的数据和程序。

三、“咽喉”MBR

主引导分区记录分为三段,第一段是446K的bootloader,第二段是硬盘分区表,第三段是硬盘有效标志(也可称魔术区)。bootloader是启动系统的核心模块,cpu根据上面安装的管理器(我们这里以最常见的grub为例)加载系统内核。

四、“光明之路”Bootloader

bootloader是系统的启动加载器。通常情况下,引导程序都安装在bootloader中。以我们常见的grup为例,grub分为stage1,stage1.5,stage2。其中stage1的代码是直接存放在mbr中的。当BIOS将控制权传递给MBR后,stage1的代码就开始运行,它主要负责将stage1.5或者stage2的内容加载在内存中。stage2被加载到内存中后,就会读取grub的配置文件grub.conf。grub.conf的主要内容如下:

[root@station47 grub]# cat grub.conf
# grub.conf generated by anaconda
#
# Note that you do not have to rerun grub after making changes to this file
# NOTICE:  You have a /boot partition.  This means that
#          all kernel and initrd paths are relative to /boot/, eg.
#          root (hd0,0)
#          kernel /vmlinuz-version ro root=/dev/mapper/vg0-root
#          initrd /initrd-[generic-]version.img
#boot=/dev/sda
#指定默认启动的内核或者os
default=0
#等待用户选择需要启动的内核或者os的时常,时间为秒
timeout=5
#启动时显示的图片
splashp_w_picpath=(hd0,0)/grub/splash.xpm.gz
#隐藏选择菜单
hiddenmenu
#启动时显示的名称
title CentOS (2.6.32-358.el6.x86_64)
#系统内核所在的磁盘root (hd0,0)
#指定内核文件及传递给内核的参数kernel /vmlinuz-2.6.32-358.el6.x86_64 ro root=/dev/mapper/vg0-root rd_NO_LUKS rd_NO_DM LANG=en_US.UTF-8 rd_LVM_LV=vg0/swap rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=auto rd_LVM_LV=vg0/root  KEYBOARDTYPE=pc KEYTABLE=us rhgb crashkernel=auto quiet rhgb quiet
#initrd为加载真正系统文件系统前加载的虚拟文件系统(在centos5.0上为虚拟磁盘initrd,在centos6.0上为initramfs虚拟文件系统)initrd /initramfs-2.6.32-358.el6.x86_64.img
[root@station47 grub]#

读取配置文件后,系统内核会初始化一部分的设备和文件,但是由于真正的系统内核是在磁盘上文件系统上的,而此时磁盘文件系统还没有被加载。并且,由于底层硬件设备平台的巨大差异,内核也不可能将全部的驱动程序都包含进来。这个时候,initramfs出马了。它是一个虚拟的文件系统,在安装操作系统的时候,一部分的安装信息和硬件驱动程序就被写入进去。这样,当grub配置文件被读取后,initramfs中的内容会被复制到rootfs中,内核从中读取必须的驱动模块,挂载真正的“根”,完成这些工作后,虚拟文件系统的内容会被复制到系统中,然后从内存中销毁。控制权被交接给/sbin/init程序来进行初始化

五、系统初始化

   /sbin/init接收到系统初始化的工作后,马上开始工作。它是所有系统进程的父进程,pid永远为1。它接管了系统的控制权先之后,它首先会去读取/etc/inittab文件来执行相应的脚本进行系统初始化,如设置键盘、字体,装载模块,设置网络等。inittab主要的任务有:

    设置系统默认的运行级别

        定义运行系统的系统初始化脚本rc.sysinit

       启动指定级别下的S开头的服务,关闭K开头的服务

       定义CtrlAltDel组合操作

       启动字符端终端

       启动图形终端

1.执行初始脚本rc.sysinit

   sysinit做了系统初始化的大部分的工作,不辞辛劳的挂载文件系统,启动相应运行级别上的服务。主要有以下内容:

   设定主机名,激活selinux和udev,挂载文件系统,激活swap,以读写方式重新挂载根文件系统,设置内核参数,设置系统时钟,键盘映射,加载额外的驱动程序。

   rc.sysinit执行完成后,系统基本上就算是启动了。可以正常工作了。但是还需要启动相关的系统服务才行。

2.执行/etc/rc.d/rc#.d脚本,根据系统inittab配置文件设定的系统运行级别,执行不同目录下的服务脚本,K开头的为关闭的服务,S开头的为需要开启的服务。

3.执行用户定义的引导程序/etc/rc.d/rc.local

我们可以自己定义属于自己的启动脚本,一般情况下可以放到该目录下。

4.初始工作完成,启动系统,看到登录界面

六、最浅薄的认识给最需要学习的自己

简单的描述了系统启动及初始化的主要流程。但是,由于初学,windows的影响,必定有很多地方认识有误,也会有很多地方遗漏。但是,奔跑的人从来不在于起步时姿势是否好看,重要的是,一直在朝着正确的方向奔跑。

最后附一张来自网络的图,非常详细和明晰,由于没有找到相关作者,这里注明是从网络上获取,谢谢作者。

wKioL1MVzZXyvCSpAAgd45S9eOg800.jpg