CentOS 系统启动流程


启动概述

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


自制CentOS系统启动流程图(PC架构)

CentOS 系统启动流程_硬件  




第一步:加电自检(POST)

   

   系统加电之后,首先进行的硬件自检,一但通电后主板会自动读取ROM(只读)中的程序,进行加载,计算机会首先加载BIOS信息,BIOS信息是如此的重要,以至于计算机必须在最开始就找到它。检查各种硬件设备是否完整存在,如内存,硬盘,显示,IO设备等。如果有硬件故障的话将按两种情况理:对于严重故障(致命性故障)则停机,此时由于各种初始化操作还没完成,不能给出任何提示或信号;对于非严重故障则给出提示或声音报警信号,等待用户处理),如果没有故障,POST完成自己

的接力任务,将尾部工作交接给BIOS处理。


第二步:系统引导过程Boot Sequence(BIOS)


  POST 过程结束后,系统的控制权从 BISO 转交到 boot loader。Boot loader 一般存储在系统的硬盘上(传统的 BIOS/MBR 系统),这个时候机器不能获取外部的存储或者网络信息,一些重要的值(日期、时间、其他外部值)都是从CMOS里读取.

  

  POST(POST-power on self test)—>ROM->CMOS(互补金属氧化物)->BIOS (Basic Input Output System,基础输入输出系统) 

  

  BIOS(Basic Input/Output System)启动初始化硬件的工作,包括屏幕和键盘,内存检测,这个过程也被成为 POST(Power On Self Test),通过ROM加载自检程序,然后按照 CMOS RAM 中设置的启动设备查找顺序,来寻找可启动设备 。注:BIOS 程序嵌在主板的 ROM 芯片上的。


  


第三步:启动加载器阶段Master Boot Loader(MBR)

      CentOS 系统启动流程_程序_02

 硬盘上第0磁道第一个扇区被称为MBR,也就是Master Boot Record,即主引导记录,决定启动介质按照BIOS所设定的系统启动流程,根据引导次序(Boot Sequence)自上而下的寻找对应存储设备上操作系统的MBR。它的大小仅有512字节,但里面却存放了预启动信息、分区表信息。可分为两部分:

    第一部分为引导(PRE-BOOT)区,占了 446个字节;

    第二部分为分区表(PARTITION TABLE),共有64个字节,每个主分区占用16字节,记录硬盘的分区信息。(这就是为什么一块硬盘只能有4个主分区)分区表有效性标记会占用2字节。 


  预引导区的作用之一是找到标记为活动(ACTIVE)的分区,并将活动分区的引导区读入内存。剩余两个字节为结束标记。寻找 grub,读取配置文件/etc/grub.conf,决定默认启动项根据MBR所指引的活动分区上寻找系统分区中的 bootloader.在bootloader当中配置了所要引导操作系统的内核所在的位置,因此BIOS被载入内存以后,当它实现将控制权限转交给bootloader以后,bootloader接收整个系统的控制权限,而后根据用户的选择去读取相应操作系统中的内核。


第四步:引导加载器阶段(GRUB加载器) 

   对于GRUB来说,一个比较好的方面就是它包含了linux文件系统的知识。GRUB能够从ext2或者ext3文件系统中加载linux内核。一旦Bootloader的第一阶段已完成MBR(启动加载器阶段),并能找到实际的引导加载程序位置,第1阶段启动加载器加载引导程序到内存中开始第二阶段。GRUB引导加载器阶段它是通过将本来两阶段的boot loader转换成三个阶段的boot loader。

stage1个阶段 :BIOS加载MBR里面的GRUB(属于第1阶段的文件),由于只有GRUB只占用446字节所以不能实现太多的功能,所以就有此阶段里面的文件来加载第1.5阶段的文件(/boot/grub下的文件)

stage1.5个阶段:这个阶段里面的就是加载识别文件系统的程序,来识别文件系统,不加载就无法识别文件系统,进而就找不到boot目录,由于GRUB是无法识别LVM,所以你不能把/boot分区设置为LVM,所以必须要把/boot单独分区    

stage2个阶段:这里面才是正在的开始寻找内核的过程,然后是启动内核

(当stage1.5的boot loader被加载并运行时,stage2 的boot loader才能被加载。)

   当stage2被加载时,GRUB能根据请求的情况显示一个可选内核的清单(在 /etc/grub.conf 中进行定义,同时还有几个软符号链接 /etc/grub/menu.lst 和 /etc/grub.conf)。你可以选择一个内核,修改其附加的内核参数。同时,你可以选择使用命令行的shell来对启动过程进行更深层次的手工控制。

/etc/grub.conf配置文件中的配置的信息:

CentOS 系统启动流程_程序_03

 在第二阶段boot loader加载到内存中后,就可以对文件系统进行查询了,同时,默认的内核镜像以及初始化内存盘镜像也被加载到内存中。

   根据grub设定的内核映像所在路径,系统读取内存映像,并进行解压缩操作。此时,屏幕一般会输出“Uncompressing Linux(解压内核中)”的提示。当解压缩内核完成后,屏幕输出“OK, booting the kernel(正在启动内核)”。


第五步:初始化kernel 

CentOS 系统启动流程_程序_04

   GRUB把内核加载到内存后展开并运行,此时GRUB的任务已经完成,接下来内核将会接管并完成。

内核一般都是压缩的,所以它的首要任务是解压缩,然后检查和分析系统的硬件并初始化内核里的硬件驱动程序。内核刚加载到内存的时候,文件系统还不能使用,它使用的是 Boot Loader 加载进内存的 initramfs。系统将解压后的内核放置在内存之中,并调用start_kernel()函数来启动一系列的初始化函数并初始化各种设备,完成Linux核心环境的建立。至此,Linux内核已经建立起来了,基于Linux的程序应该可以正常运行了。


  1. kernel主要是完成系统硬件探测及硬件驱动的初始化,并且以读写的方式挂载根文件系统(根切换)kernel初始化所要工作的内容做下简单总结:

探测硬件—>加载驱动—>挂载临时根文件系统(initrd)—>切换至根文件系统(rootfs)—>运行/sbin/init完成系统初始化

   

第六步:挂载Initial RAM Disk(/boot/initrd)

   

  initrd是"initial RAM disk"的缩写,随kernel一起被GRUB加载进内存,在系统引导过程中挂载的一个临时根文件系统。 Linux内核在设计风格上属于单内核,文件系统、进程管理、内存管理都需要内核来完成,这样势必会造成内核代码非常庞大。为了减少linux内核的大小,Linux系统内核被分成了内核和内核模块,内核会根据平台需要动态加载内核模块,非核心功能通常做成内核模块,比如大多数设备驱动。 这样势必会产生矛盾,比如,如果Linux内核中没有集成识别ext3文件系统的模块,而ext3模块却在ext3文件系统中。这时,Linux内核访问文件系统需要拿到这个模块,而这个模块又在文件系统中。这样就能看出使用initrd的必要了


   要访问根文件系统必须要加载根文件系统所在的设备,而这时根文件系统又没有挂载,initrd在内存中挂接成内存中的文件系统,内核先将initrd内存中的文件系统当成根来进行挂接,运行initrd内部的initrd程序(这个initrd程序其实是一个脚本,这个脚本加载了一系列配置),那么这个initrd又起到了什么作用哪?


CentOS 系统启动流程_Linux_05


initrd展开后的文件    CentOS 系统启动流程_程序_06  

linux中/下的文件      CentOS 系统启动流程_Linux_07


      我们可以看到,其实initrd文件其实是一个虚拟的根文件系统,里面有bin、lib、lib64、sys、var、etc、sysroot、dev、proc、tmp等根目录,其实你会发现里面的目录有点像真的/对吧,所以我们称之为虚拟的根文件系统,作用就是将kernel和真的根文件系统建立关联关系,让 kernel去initrd中加载根文件系统所需要的驱动程序,并以读写的方式挂载根文件系统,并让执行用户当中第一个进程init。


第七步:切换根目录


   kernel藉此完成驱动程序的加载,最终释放虚拟文件系统,并挂载实际的根目录文件系统.switchroot切换根目录,该命令的的结果是把当前根目录的设置从initrd转换为硬盘上真正的根目录。


第八步:启动init进程,读取/sbin/inittab


   内核在完成核内引导以后,即在本线程(进程)空间内加载init程序,它的进程号是1。init进程是所有进程的发起者和控制者。因为在任何基于Unix的系统中,它都是第一个运行的进程,所以init进程的编号(Process ID,PID)永远是1。如果init出现了问题,系统的其余部分也就随之而垮掉了。

  /sbin/inittab进程是系统所有进程的起点,你可以把它比拟成系统所有进程的老祖宗,没有这个进程,系统中任何进程都不会启动。/sbin/init 最主要的功能就是准备软件运行的环境,包括系统的主机名称、网络配置、语系处理、文件系统格式及其他服务的启动等,它是其他所有进程的父进程。

所有的动作都根据在/etc/inittab中的配置.将会执行/etc/inittab来设定系统运行的默认级别.

   

第九步:设置系统的运行级别


在 niittab 中有一个很重要的设置选项 runlevel 。根据 runlevel 的不同启动不同的服务,让 Linux 的使用环境不同。基本上 runlevel 分为 0-6 , 7 个等级:

    0-6:7个级别的定义

     0:关机, shutdown

    1:单用户模式(singleuser),root用户,无须认证;维护模式;

     2:多用户模式(multiuser),会启动网络功能,但不会启动NFS;维护模式;

    3:多用户模式(mutliuser),完全功能模式;文本界面;

     4:预留级别:目前无特别使用目的,但习惯以同3级别功能使用;

     5:多用户模式(multi user),完全功能模式,图形界面;

     6:重启,reboot


   许多程序需要开机启动。它们在Windows叫做"服务"(service),在Linux就叫做"守护进程"(daemon)。init进程的一大任务,就是去运行这些开机启动的程序。但是,不同的场合需要启动不同的程序,比如用作服务器时,需要启动Apache,用作桌面就不需要。

Linux允许为不同的场合,分配不同的开机启动程序,这就叫做"运行级别"(runlevel)。也就是说,启动时根据"运行级别",确定要运行哪些程序。

第十步系统初始化脚本文件/etc/rc.d/rc.sysinit

可以看到,init进程通过执行/etc/rc.d/rcS.conf首先调用了/etc/rc.d/rc.sysinit,对系统做初始化设置,设置好整个系统环境。我们来看看这个脚本都是做了些什么哪?

CentOS 系统启动流程_硬件_08

   事实上init执行/etc/rc.d/rc.sysinit的初始化将会做很多设置:

      1、获得网络环境 

      2、挂载设备 

      3、开机启动画面Plymouth(取替了过往的 RHGB) 

      4、判断是否启用SELinux 

      5、显示于开机过程中的欢迎画面 

      6、初始化硬件 

      7、用户自定义模块的加载 

      8、配置内核的参数 

      9、设置主机名 

      10、同步存储器 

      11、设备映射器及相关的初始化 

      12、初始化软件磁盘阵列(RAID) 

      13、初始化 LVM 的文件系统功能 

      14、检验磁盘文件系统(fsck) 

      15、设置磁盘配额(quota) 

      16、重新以可读写模式挂载系统磁盘 

      17、更新quota(非必要) 

      18、启动系统虚拟随机数生成器 

      19、配置机器(非必要) 

      20、清除开机过程当中的临时文件 

      21、创建ICE目录 

      22、启动交换分区(swap) 

      23、将开机信息写入/var/log/dmesg文件中

第十一步:关闭或启动对应级别下的服务/etc/rc.d/rc.n


      设定玩系统默认运行级别以后,接着调用/etc/rc.d/rc脚本,/etc/rc.d, 里面存放了rc.local, rc.sysinit, init.d, rcX.d (X包括0-6对应相对runlevel).这个脚本接收默认运行级别参数后,依脚本设置启用或停止/etc/rc.d/rc[0-6].d/中相应的程序,如下图,看一下我系统运行默认级别(级别)3下的内容吧

CentOS 系统启动流程_硬件_09

    如图示,/etc/rc.d/rc3].d/下的脚本文件在系统初始化阶段,脚本名字以K开头的,表示STOP动作(关闭),名字以S开头,表示Start动作(启动),文件名K/S 后面的的数字代表优先级,名称中的数字表示执行次序(优先级),数字越小表示越先执行,优先级越高

第十二步:用户自定义开机启动程序 (/etc/rc.d/rc.local)

  系统根据runlevel启动完rcX.d中的脚本之后,会调用rc.local脚本,如果你有一个脚本命令不论在3和5都想开机启动,那么就添加于此,免去rc3.d和rc5.d分别增加启动脚本工作量.最后,将执行/etc/rc.d/rc.local脚本,可以根据自己的需求将一些执行命令或者脚本写到其中,当开机时就可以加载。

第十二步:打印登录提示符

   系统初始化完成后,init给出用户登录提示符(login)或者图形化登录界面,用户输入用户和密码登陆后,系统会为用户分配一个用户ID(uid)和组ID(gid),这两个ID是用户的身份标识,用于检测用户运行程序时的身份验证。登录成功后,整个系统启动流程运行完毕!