Linux系统启动流程

1、POST开机自检:

       计算机中有一个神秘的软件,它被永久地记录在ROM中,是 操作系统输入输出管理系统的一部分。他就是BIOS (Basic Input/Output System ),中文名字为基本输入输出系统。早期的BIOS芯片是只读的,而现在的主板都有一种叫Flash EPROM的芯片 来存储系统BIOS,里边的内容可通过使用主板厂商 提供的擦写程序擦除后重新写入。

BIOS的功能由两部分组成,POST和Runtime服务。POST阶段完成后它将从存储器中被删除,而Runtime服务会被一致保留,用于目标操作系统的启动。BIOS两个阶段所做的工作如下:

       步骤一:开机自检POST(Power-on self test),主要负责监测系统外围关键设备(如CPU、内存、显卡、I/O、键盘鼠标等)是否正常。例如当显卡松动时候,BIOS自检阶段就会报错,系统无法启动;

       步骤二:自检成功之后,便会执行一小段程序来枚举本地设备并对其初始化。这一步主要是根据我们在BIOS中设置的系统启动顺序来搜索用于启动系统的驱动器,如硬盘、光盘、U盘、软盘和网络等。如下图所示:

wKioL1aOb1ShDJXKAACPzzS1X3Q475.png

   图1 BIOS启动顺序    

    以硬盘启动为例,BIOS此时去读取硬盘驱动的第一个扇区(MBR,512字节),然后执行里边的代码。此时BIOS的任务就完成了,此后 系统启动的控制权移交到MBR了。

2、系统引导

MBR : Master Boot Record,位于硬盘0个柱面、0磁头、1扇区(001)称为主引导扇区。

MBR共有512个字节,它有三个部分组成:

  • 前446bytes:Bootloader(主引导记录)

  • 64bytes:Disk Partition Table (硬盘分区表DPT)

  • 2bytes:硬盘有效标志(55AA)

如下图所示

图2 MBR结构

DPT(磁盘分区表)主要包含以下三个部分:

a、Parttition ID ( 82:Swap   83:Linux    8e:LVM    fd:RAID)

b、Partition起始柱面

c、Partition的柱面数量

DPT(磁盘分区表)仅有64个字节,每16个字节确定一个分区,所以在DPT中主分区+扩展分区最多只能 有4个,且标识ID为1-4,逻辑分区编号从5开始。扩展分区仅仅是一个逻辑概念,不能直接使用,需要在其上边增加逻辑分区,从而指向存储文件的路径。

Linux操作系统中常见的引导程序有LILO、GRUB等都直接安装在MBR中,LILO存在一些缺陷――其无法加载容量较大的硬盘,一般大于1024个柱面就无法加载了。现在比较常用的是GRUB,我们也以GRUB为例来分析引导过程。

      GRUB引导分为两个阶段:stage1阶段和stage2阶段(还有一些grub定义了stage1.5阶段)。

    1)、stage1:stage1是直接被写入MBR中去的,这样机器已启动检测完硬件后,就将控制权交给了GRUB了。在MBR前446bytes的空间中存放的是stage1的代码,BIOS找到启动设备后,就将stage1(stage1/start.S)载入内存中执行。stage1没有识别文件系统的能力,所以其任务非常简单,仅仅是将硬盘0磁头、0柱面、2扇区读入内存。

    2)、如果此GRUB中存在stage1.5阶段,stage1就将stage1.5阶段读入内存中。stage1.5阶段作为stage1和stage2中间的桥梁,stage1.5有识别文件系统额能力,因此grub才能有能力去加载/boot/grub目录下的stage2文件,将stage2载入内存中并执行。

        (注:如果GRUB中没有stage1.5阶段,那么stage1直接将stage2阶段读入内存中。这样stage2不是/boot分区/boot/grub/目录下的stage2文件,这时候stage2存放在/boot分区的Boot Sector的stage2。由stage2加载内核,也就是没有第3)步了。不过这种情况有一个限制:因为stage1通过BIOS中断方式直接对硬盘寻址,而非通过访问具体额文件系统。其寻址范围限制在8GB以内,因此这种情况需要将/boot分区在硬盘8GB寻址空间之前)。

    3)、stage2阶段:其实Bootloader是装载在grub的stage2阶段的,stage2阶段在磁盘上/boot/grub中的stage2文件。它可以提供一个操作系统启动之前的系统,不受MBR的限制。提供一个交互式接口、背景图、一些启动选项等。启动stage2之后由stage2以它的丰富功能去加载内核。

3、内核启动

       当stage2被载入内存中执行时,它首先会解析grub的配置文件/boot/grub/grub.conf,然后加载内核镜像到内存中,并将控制权交给内核。

        新官上任三把火,当内核开始掌权时,内核开始进行初始化操作:

  • 探测可识别到的所有硬件设备 ,其中包括CPU、I/O、存储设备等;

  • 加载硬件驱动程序;

  • 以只读方式挂载根文件系统;

  • 运行、用户空间的第一个应用进程:/sbin/init

       Linux内核需要适应多种不同的硬件架构,但是将所有的硬件驱动编入内核是不实际的,而且内核也不能新出一个驱动就编入内核中。在系统安装过程中会检测硬件信息,将一部分驱动写入 /boot/initrd,这样启动后一部分设备驱动就放在initrd来加载。在这里多说一点,解释一下initrd这个家伙。

     initrd(bootloader initialized RAM disk)就是bootloader初始化的内存盘。在Linux2.6内核启动之前,bootloader会将存储介质中的initrd文件加载到内存,内核启动时会访问真正的根文件系统前先访问内存中的initrd文件系统(initramfs)。在bootloader配置了initrd的情况 下,内核启动分成了两个阶段:第一阶段先执行initrd文件那个中的init,完成加载驱动模块等任务,第二阶段才会执行真正的更稳健系统中的 /sbin/init进程。

      另外一个概念:initramfs

       它的意义就是:在内核镜像中附加一个cpio包,这个车票包中包含了一个小型的 文件系统,当内核启动时,内核将这个cpio包解开,并将其包含额文件系统释放到rootfs中,内核中的一部分初始化代码就会放到这个文件系统中,作为用户层进程来执行。这样带来的明显好处就是精简了内核的初始化代码,而且使得内核的初始化过程更容易定制。

     总体来说:

     Stage2将initrd加载到内存中,内核去执行initrd的init脚本,这时内核将控制权交给了init文件处理。Init主要是加载各种存储介质相关的设备驱动程序。当所需的驱动程序加载后会创建一个根设备,将根文件系统rootfs以只读挂载。此步骤完成后,释放未使用的内存,切换至真正的根文件系统,同时运行/sbin/init程序,执行系统的1号进程。

4、初始化系统:

       /sbin/init进程是系统中所有进程额父进程,当它接管控制权后,首先会读取/etc/inittab文件来执行相应脚本进行系统初始化,如设置键盘、字体,装载模块,设置昂罗等。主要工作如下:

   1)、执行系统初始化脚本(/etc/rc.d/rc.sysinit),对系统进行基本的配置,以读写方式 挂在根文件系统及其他文件系统,此时Linux操作系统基本上运行起来了,后面需要进行运行级别确定及相应服务的启动。rc.sysinit所做额事情如下:

    (1)、获取网络环境与主机类型,首先会读取网络环境设置文件“/etc/sysconfig/network",获取主机名称与默认网关等网络环境。

    (2)、测试与载入内存设备/proc及usb设备/sys。

    (3)、是否启用 SELinux/

    (4)、挂载/etc/fstab 文件中定义的文件系统;

    (5)、检测根文件系统,并以读写方式重新挂载根文件系统;

    (6)、 用户自动以加载的模块。用户可以在/etc/sysconfig/modules/*.modules加入自定义模块,此时会加载到系统中;

    (6)、按”/etc/sysctl.conf"这个文件的设置值配置内核参数;

    (7)、设置系统时间;

    (8)、激活lvm及 软RAID;

    (9)、激活swap设备;

    (10)、加载额外设备驱动程序;

     (11)、清理启动过程中产生额临时文件;

    (12)、将启动信息加载到/var/log/dmesg文件中。

      当/etc/rc.d/rc.sysinit执行完成后,系统就可以顺利工作了,只是还需要启动系统所需要的各种服务,这样主机能提供相关的网络和主机功能,因此会执行下边的脚本。

      CentOS 5系统:

        2)、执行/etc/rc.d/rc脚本。该文件定义了服务启动的顺序,先K后S,而 具体的每个运行级别的服务状态是放在/etc/rc.d/rc*.d(*=0~6)目录下,所有的文件均是指向/etc/init.d下相应的符号链接。rc.sysinit通过分析/etc/inittab文件来确定系统启动级别,然后才去执行/etc/rc.d/rc*.d下的文件。

    /etc/init.d-->/etc/rc.d/init.d

    /etc/rc -->/etc/rc.d/rc

    /etc/rc*.d-->/etc/rc.d/rc*.d

    /etc/rc.local-->/etc/rc.d/rc.local

    /etc/rc.sysinit-->/etc/rc.d/rc.sysinit

       也就是说,/etc目录下的init.d、rc、rc*.d、rc.local和rc.sysinit均是指向/etc/rc.d目录下相应文件和文件夹额符号链接。 以启动级别3为例来简要说明一下:

        /etc/rc.d/rc3.d目录,该目录下的内容全部是以S或K开头的链接文件,这些链接文件都链接到/etc/rc.d/init.d目录下的脚本。S表示开机时启动,K表示关闭的服务内容。/etc/rc.d/rc*.d中系统服务会在系统后台启动,如果要对某个运行级别中的服务进行更具体额定制,可使用chkconfig命令来操作,或和通过setup、ntsys、system-config-services 来定制(我感觉chkconfig还是比较好用)。如果要增加启动内容,可在init.d目录中增加shell脚本,然后在rc*.d中穿件链接文件指向shell脚本。这些hell脚本启动和结束顺序是有S或K后边的数字决定的,数字越小脚本越先执行。没错,这个数字就是优先级了。

        3)、执行用户自定义引导程序/etc/rc.d/rc.local。其实当执行/etc/rc.d/rc3.d/S99local时,他就是在执行/etc/rc.d/rc.local,S99local其符号链接。自定义的程序只需要放在rc.local里面就OK了,这个shell就是给咱自定义启动内容的。有没有发现S99local ,99耶,优先级最小的一个shell了,也就是说系统完成启动执行的最后一个shell脚本。

        4)、完成了系统有额启动任务后,就开始 启动终端或X-Window等待用户登录。tty1、tty2...tty6,这些就是说我们一共能启动6个终端,这6个终端在运行1,2,3,4的时候都会执行/sbin/mingetty,而且执行了6个,所以Linux会有6个纯文本终端,mingetty就是终端启动命令。当然除了这6个终端还会执行/etc/X11/prefdm-nodaemon ,这就是启动X-Window的命令了。

至此Linux操作系统启动完毕了。概括一下初始化系统用户空间系统启动的流程为:

设定默认运行级别(/etc/inittab)-->运行系统初始化脚本(/etc/rc.d/sysinit)-->关闭或启动对应级别下需要停止或开启的服务(/etc/rc.d/rc*.d/{S|K}##* 和 /etc/rc.d/rc.local)-->设置登录终端(/sbin/mingetty-->启动图形终端(/etc/X11/prefdm-nodaemon)。

    CentOS 6:

        对于CentOS6而言,init程序已经更改为upstart,但依然为/sbin/init。其配置文件为/etc/init/*.conf 。这些用于运行所应用到的服务脚本就在/etc/init/*.conf中,例如系统初始化脚本为/etc/init/rcS.conf,起始该脚本调用执行的还是/etc/rc.d/rc.sysinit;启动终端的脚本为:/etc/init/start-ttys.conf。同时CentOS 6 为了兼容CentOS 5 依然会调用/etc/inittab脚本,只不过这个脚本仅用来设定默认级别的。

        以上就是我站在巨人的肩膀行总结的启动流程,有错误的地方期望大家指正。最后附一张图,以示本文:

wKiom1aQcBzgd1hPAAbWljIq5cY861.jpg

你可能感兴趣的:(linux启动流程)