Linux 系统启动流程

内核简介:
  kernel功能:进程管理、内存管理、网络管理、驱动程序、文件系统、安全功能
  库:函数的集合,同时提供调用接口;不能作为程序的执行入口单独执行,只能被程序调用
  过程调用:procedure,无返回结果
  函数调用:function,有返回结果

  内核设计流派:
  单内核设计:把所有功能模块集成于同一个程序(Linux)
  微内核设计:每种功能模块使用一个单独子系统实现(Windows、Solaris)
  Linux内核特点:
  支持模块化:*.ko(内核模块文件)如:文件系统,硬件驱动,网络协议等
  支持模块的动态装载和卸载

  Linux内核组成部分:
  核心文件:/boot/vmlinuz-Version-Release
  ramdisk:辅助的伪根文件系统
    CentOS 5: /boot/initrd-Version-Release.img
    CentOS 6、7: /boot/initramfs-Version-Release.img
  模块文件:/lib/modules/Version-Release/

Linux启动流程:
  Centos5、6启动流程:POST—>Boot Sequence(BIOS)—>Boot Loader (MBR)—>Kernel(ramdisk)—> rootfs (readonly)—>switchroot—>/sbin/init—>(/etc/inittab, /etc/init/*.conf)—>设定默认运行级别—>系统初始化脚本—>关闭或启动对应级别下的服务—>启动终端—>登陆系统(登陆界面环境)—>启动shell(shell环境)。

  POST(Power OnSelf Test)加电自检
  POST它首先对每一个硬件设备进行检查。完成后会寻找存有引导记录的设备,找到之后读入操作系统引导记录,然后将系统控制权交给引导记录,并由引导记录来完成系统的顺利启动。

  Boot Sequence(BIOS)
  在系统启动之前不知道计算机的系统在哪里,所以在计算机的bios上定义了设备启动顺序,它会安照设备的启动顺序去查找引导加载器。

  Boot Loader(MBR)
  MBR:Master Boot Record 主引导记录在可引导设备的前512bytes中(硬盘的第一个扇区),前446bytes为bootloader,接下来的64bytes为分区表信息,最后2bytes标记为55AA(表示为可引导设备)
  Boot loader引导加载器,用来引导系统的启动,它把用户选定的内核加载到内存空间中,把控制权交给内核。
  Windows下引导加载器:ntloader
  Linux下引导加载器:
    LILO:LInux LOader
    GRUB:GRand Unified Bootloader
      GRUB Legacy 0.X 传统版本为0.X
      GRUB2    1.X 与传统版本完全不一样的1.X版本
    功能:提供一个菜单,允许用户选择要启动的系统或内核版本;把用户选定内核装载到RAM的特定空间中并解压展开,而后把系统控制权移交给内核;
    MBR所给予的空间毕竟太小,容不下较大的引导程序,因此grub程序被分为三段:"stage 1" 被装入磁盘的MBR中;特殊的"stage 1.5"被装入MBR随后的扇区,它能够识别内核和"stage 2"所在分区的文件系统格式并帮助引导"stage 2",它是"stage 1"和"stage 2"之间的纽带;"stage 2"位于文件系统上。stage 2程序和grub.conf可以与内核文件处于不同的分区上(但必须位于同一磁盘),只要"stage 1.5"能够驱动它们各自所在的分区。
    GRUB引导过程分为三段:
      stage1:MBR(0柱面0磁道1扇区)
      stage1_5:MBR随后的扇区
      stage2:读取grub.conf配置文件,并实现引导功能的扩展

  Kernel:加载系统内核,执行系统初始化信息
  在GRUB中选定内核进入,内核会对自身初始化;探测可识别到的所有硬件设备,加载硬件驱动程序(有可能需要借助ramdisk加载驱动);以只读方式挂载根文件系统;运行用户空间的第一个应用程序:/sbin/init
 Centos5:initrd
  initrd文件生成工具程序:mkinitrd
  Centos6,7:initramfs(cpio格式)
  initramfs文件生成工具程序:dracut、mkinitrd

 ramdisk:Linux内核的特性之一,使用缓冲和缓存来加速对磁盘上的文件访问:
  为什么将initrd改为initramfs,前者把内存模拟成磁盘,后者直接把内存模拟成文件系统;如果模拟成磁盘,将磁盘加载到内存中,内核需将initrd再次缓存到内核的内存空间当中,相当于在内存中缓存两次;但是如果模拟成文件系统,内核可以直接访问文件系统所在的内存空间,这样效率更高性能更好
  initrd 、initramfs都属虚拟文件系统,在早期的linux系统中,一般只有硬盘或者软盘被用来作为Linux根文件系统的存储设备,因此也就很容易把这些设备的驱动程序集成到内核中。但是现在的Linux系统中可能将根文件系统保存到各种存储设备上,包括scsi、sata,usb-disk等等。如果把这些设备的驱动代码全部编译到内核中内核会很庞大。
  为了解决这一矛盾,于是出现了基于ramdisk的initrd( bootloader initialized RAM disk )。initrd是一个被压缩过的小型根目录,这个目录中包含了启动阶段中必须的驱动模块、可执行文件和启动脚本。当系统启动的时候bootloader会把initrd文件读到内存中,然后把initrd文件在内存中的起始地址和大小传递给内核。内核在启动初始化过程中会解压缩initrd文件,然后将解压后的initrd挂载为根目录,并执行根目录中的/linuxrc脚本(cpio格式的initramfs为/init,而image格式的initrd为/linuxrc),脚本会加载真实文件系统中存放的设备驱动程序,以及在/dev目录下创建必要的设备节点。这样就可以mount真正的根目录,并切换到这个根目录中。

  Linux 发行版在内核中只编译了基本的硬件驱动,在Linux系统安装过程中通过检测系统硬件,生成包含安装系统硬件驱动的initrd,在内核引导过程中先加载initrd虚拟文件系统,然后由initrd挂载真正的文件系统,完成后initrd从RAM中退出,并不消耗内存,initrd只是一个暂时的文件系统。
  在Linux2.5内核中出现了initramfs,它的作用和initrd类似,只是和内核编译成一个文件(initramfs是经过gzip压缩后的cpio格式文件),该cpio格式的文件被链接进了内核中特殊的数据段.init.ramfs上,其中全局变量__initramfs_start和__initramfs_end分别指向这个数据段的起始地址和结束地址。内核启动时会对.init.ramfs段中的数据进行解压,然后使用它作为临时的根文件系统。

  initrd与initramfs的区别:
  initrd是init ram disk,initramfs是init ram file system,前者把内存模拟成磁盘,后者直接把内存模拟成文件系统
  cpio-initrd(initramfs)的处理流程
    1、boot loader 把内核以及 initrd 文件加载到内存的特定位置
    2、内核判断initrd的文件格式,如果是cpio格式
    3、将initrd的内容解压到rootfs中
    4、执行initrd中的/init文件,切换到真实的根文件系统,执行/sbin/init
  image-initrd(initrd)的处理流程
    1、boot loader把内核以及initrd文件加载到内存的特定位置。
    2、内核判断initrd的文件格式,如果不是cpio格式,将其作为image-initrd处理。
    3、内核将initrd的内容保存在rootfs下的/initrd.image文件中。
    4、内核将/initrd.image的内容读入/dev/ram0设备中,也就是读入到一个内存盘中。
    5、接着内核以可读写的方式把/dev/ram0设备挂载为原始的根文件系统。
    6、如果/dev/ram0被指定为真正的根文件系统,那么内核跳至最后一步正常启动。
    7、执行initrd上的/linuxrc文件,linuxrc通常是一个脚本文件,负责加载内核访问根文件系统必须的驱动, 以及加载根文件系统。
    8、/linuxrc执行完毕,真实的根文件系统被挂载
    9、如果真实根文件系统存在/initrd目录,那么将/dev/ram0从/移动到/initrd;如果不存在/initrd目录,/dev/ram0将被卸载。
    10、在真实根文件系统上进行正常启动过程 ,执行/sbin/init。

  init程序:启动用户空间的第一个程序/sbin/init,完成系统初始化
  在内核、硬件及驱动信息加载完毕后,内核会呼叫用户空间中的第一个执行程序/sbin/init,init程序主要功能是准备软件运行环境,包括系统的主机名称、网络配置、文件系统格式等其他服务的启动管理。而这些所有的操作都是通过init的配置文件来定义
  一旦启动了init,内核就不管了,所有的后续操作都是由init去加载运行用户空间的应用程序来完成各种各样的工作,只有当这些应用程序完成系统调用或者系统发生中断时需要特权操作时,内核才会参与;剩余的其它过程都不在参与,而是由用户空间的程序来完成

  init程序的类型:
  Centos 5:SysV init
  由于Centos5采用的是SysV init方式,其特点是启动用户空间的服务程序,通常通过脚本进行,有依赖关系的服务将被串行启动;这也就导致了Centos5的系统启动过程非常缓慢
  配置文件:/etc/inittab

  Centos 6:Upstart,但程序名依然为/sbin/init
  采用Upstart的方式,其特点是守护进程间的通信依赖于D-Bus进行,因此,可基本实现类似并行启动
  配置文件:centos6中/etc/inittab中只是部分配置文件,大多数配置文件在/etc/init/*.conf(*.conf为upstart风格的配置文件)

  Centso 7:Systemd
  采用Systemd方式,其特点是服务只有在第一次被访问时才会真正启动起来;因此Centos 7系统的启动过程非常快
  配置文件:一部分在/usr/lib/systemd/system/目录下,另外一部分在/etc/systemd/system/目录下;Systemd完全兼容SysV脚本机制;因此service命令依然可用;不过建议使用systemctl命令来控制服务;

运行/sbin/init程序—>读取/etc/inittab文件获得运行级别—>运行系统初始化脚本/etc/rc.d/sysinit—>运行/etc/rc#.d/

  系统运行级别:
  Centos 6:Upstart兼容了centos 5的init
  运行级别:为了系统的运行或维护等目的而设定的机制;一共7(0-6)个级别
  0:关机,shutdown
  1:单用户模式(single user),以root用户登陆,无需认证;维护模式
  2:多用户模式(multi user),会启动网络功能,但不会启动NFS;维护模式
  3:多用户模式,完全功能模式;文本界面
  4:预留级别;目前无特别使用目的,但习惯以同3级别功能使用
  5:多用户模式,完全功能模式,图形界面
  6:重启,reboot
  默认运行级别:3或5
  运行级别切换:init #
  查看当前级别:
  who –r
  runlevel

  配置文件:/etc/inittab
  每行定义一种action以及与之对应的process
  id:runlevels:action:process
  id:一个任务的标识符,可以自己定义只要不重复
  runlevels:在哪些级别启动此任务;#,###,也可以为空,表示所有级别
  action:在什么条件下启动此服务;常用action有以下4种
    wait:等待切换至此任务所在的级别时执行一次
    respawn:一旦此任务终止,就自动重新启动之
    initdefault:设定默认运行级别;此时process省略
    sysinit:设定系统初始化方式,process一般会指定/etc/rc.d/rc.sysinit脚本
    process:任务,要执行的程序
例如:
id:3:initdefault: 设定系统默认运行级别为3级别(如果个内核传递了运行级别参数,以传递的参数为准)
si::sysinit:/etc/rc.d/rc.sysinit 设置系统初始化方式为运行/etc/rc.d/rc.sysinit脚本
运行指定运行级别下的服务脚本:
l0:0:wait:/etc/rc.d/rc 0  在0运行级别运行/etc/rc.d/rc脚本,并给脚本传递了参数0
l1:1:wait:/etc/rc.d/rc 1
l2:1:wait:/etc/rc.d/rc 2
l3:1:wait:/etc/rc.d/rc 3
l4:1:wait:/etc/rc.d/rc 4
l5:1:wait:/etc/rc.d/rc 5
l6:6:wait:/etc/rc.d/rc 6
  rc脚本接受一个运行级别数字为参数,"/etc/rc.d/rc #"意味着去运行去/etc/rc.d/rc#.d/目录下的服务脚本,这些脚本用来控制对应级别下服务的启动或停止(按优先级顺序执行);
  K##*:以K开头的是要停止的服务;##是优先级,数字越小越优先关闭;依赖别的服务才能启动的服先关闭,被依赖的服务后关闭;
  S##*:以S开头要启动的服务;##是优先级,数字越小越优先启动;被依赖的服务先启动,依赖别的服务才能启动的服务后启动;
  /etc/rc.d/rc#.d/目录下的文件软连接到/etc/rc.d/init.d/目录中的脚本

  系统初始化脚本功能:/etc/rc.d/rc.sysinit
  1、设置主机名
  2、设置欢迎信息
  3、激活udev和selinux
  4、挂载/etc/fstab文件中定义的所有文件系统
  5、检测根文件系统,并以读写方式重新挂载根文件系统
  6、设置系统时钟
  7、根据/etc/sysctl.conf文件来设置内核参数
  8、激活lvm以及软raid设备
  9、激活swap设备
  10、加载额外设备的驱动程序
  11、清理操作

  服务启动脚本:
  /etc/init.d/*(/etc/rc.d/init.d/*)不同发行版可能路径不一样
  脚本执行方式:
  /etc/init.d/Server_Script {start|stop|restart|status}
  service Server_Script {start|stop|restart|status}

  设置服务在不同系统运行级别下的启动和关闭:
  chkconfig命令:管控/etc/init.d/每个服务脚本在各级别下的启动或关闭状态
  查看:chkconfig --list [name]
    chkconfig --list 查看全部服务在各级别下的状态
    chkconfig --list Name 查看指定服务在各级别下的状态

  添加:chkconfig --add name
  能被添加的服务的脚本定义格式之一:
    #!/bin/bash
    #chkconfig: LLL NN MM
   #description:
    LLL 指定的级别需要启动该服务,没指定的级别关闭该服务;如果是"-"表示7个级别该服务都是关闭的
    NN  启动服务时的优先级
    MM  停止服务时的优先级

  删除:chkconfig --del name

  修改指定服务在指定运行级别下的状态:
  chkconfig [--level LEVELS] name<on|off|reset>
    --level LEVELS 指定要控制的级别,不指定默认为2345

  注意:正常级别下,最后一个启动项(/etc/rc.d/rc#.d/)是一个S99local的服务,没有链接至/etc/init.d下的某脚本,而是链接至/etc/rc.d/rc.local(/etc/rc.local)脚本;因此不便或不需写为服务脚本的程序但是又希望能开机自动运行时,直接放置于此脚本文件中即可。

  设置登录终端:/etc/inittab
  tty1:2345:respawn:/usr/sbin/mingetty tty1 2345运行级别启动tty1,下面依次启动其他5个虚拟终端
  tty2:2345:respawn:/usr/sbin/mingetty tty2
  tty3:2345:respawn:/usr/sbin/mingetty tty3
  tty4:2345:respawn:/usr/sbin/mingetty tty4
  tty5:2345:respawn:/usr/sbin/mingetty tty5
  tty6:2345:respawn:/usr/sbin/mingetty tty6
  1、mingetty会调用login程序
  2、打开虚拟终端的程序除了mingetty之外,还有诸如getty等

  总结:用户空间的启动流程
  /sbin/init(/etc/inittab)设置默认运行级别
  运行系统初始化脚本/etc/rc.d/rc.sysinit,完成系统的初始化
  运行/etc/rc.d/rc#.d/目录下面的脚本(实际是连接到/etc/rc.d/init.d/目录下的脚本)关闭对应级别下的需要停止的服务,启动对应级别下需要开启的服务;
  设置登录终端

  CentOS系统的启动流程包括:内核空间的启动流程和用户空间的启动流程
  参考启动流程图一

  参考启动流程图二

 

原文地址:https://www.cnblogs.com/Link-Luck/p/9858519.html