1、Linux启动过程概述

1.1、启动过程

启动过程.png

上图中,有 GRUB、GRUB2、init、systemd 等几个概念,下面做一下简单的说明。

GRUB2 相较于 GRUB 的提升:更健壮、可移植、更强大。支持 Legacy BIOS、EFI 和 OpenFirmware,支持 GPT 和 MBR 分区表。支持非 Linux 系统,如苹果 HFS 文件系统和 Windows 的 NTFS 文件系统。

systemd 被设计用来改进 sysvinit 的缺点,它和 Ubuntu 的 upstart 是竞争对手,然而从 Ubuntu 15.04 开始,Ubuntu 开始逐步使用 systemd 替代 Upstart 初始化系统。

systemd 的目标是:尽可能启动更少进程;尽可能将更多进程并行启动。systemd 尽可能减少对 shell 脚本的依赖。传统 sysvinit 使用 inittab 来决定运行哪些 shell 脚本,大量使用 shell 脚本被认为是效率低下无法并行的原因。systemd 使用了 Linux 专属技术,不再顾及 POSIX 兼容。

1.2、init 和 systemd 的区别

  • init

    • init 是串行启动,只有前一个进程启动完,才会启动下一个进程,因此启动速度慢
    • 由于是串行启动,当有某一个 shell 脚本被堵塞了,系统将无法正常启动
    • init 启动脚本采用 shell 脚本编写,具有编写脚本复杂、执行效率低等缺点
    • 由 Linux 内核加载运行,位于 /sbin/init ,是系统中第一个进程,PID 永远为 1
    • Init 进程的配置文件
参数说明
/etc/init.d/服务启动脚本配置文件存放目录
/etc/inittab默认运行级别配置文件
/etc/init/rcS.conf系统初始化配置文件
/etc/init/rc.conf各运行级别初始化的配置文件
/etc/init/rcS-sulogin.conf单用户模式启动 /sbin/sushell 环境的配置文件
/etc/init/control-alt-delete.conf终端下的 ctrl+alt+del 热键操作的配置文件
/etc/sysconfig/inittty终端的配置文件
/etc/init/start-ttys.conf配置tty终端的开启数量、设备文件
/etc/init/tty.conf 或 /etc/init/serial.conf控制tty终端的开启
  • systemd

    • 并行启动,缩短启动时间
    • 无启动脚本,改成配置文件的方式定义服务的启动
    • 由Linx内核加载运行,位于 /usr/lib/systemd/systemd,是系统中第一个进程,PID 永远为 1
    • systemd 进程的配置文件
参数说明
/etc/systemd/system/default.target取代/etc/inittab文件配置,通常符号链接到 /lib/systemd/system/graphical.target
/run/systemd/system/系统执行过程中所产生的服务脚本所在目录
/etc/systemd/system/里面存放着不同级别的开启自启服务
/usr/lib/systemd/system/每个服务最主要的启动脚本设置,类似于之前的 /etc/init.d/

1.3、运行级别概念

Linux 有 7 个运行级别,以数字 0-6 来表示。

运行级别说明RHEL6命令RHEL7命令
0关机状态,使用该级别将会关机init 0poweroff
1系统救援模式,多用于系统维护init 1systemctl isolate rescue.target
2字符界面的多用户模式(不可访问网络)init 2systemctl isolate mutil-user.target
3字符界面的完整多用户模式,大多数服务器主机运行此级别init 3systemctl isolate mutil-user.target
4未分配使用init 4systemctl isolate mutil-user.target
5图形界面的多用户模式,提供了图形桌面操作环境init 5systemctl isolate graphical.target
6重新启动主机init 6reboot

2、深入了解Linux引导过程

2.1、第一步:开机自检

2.2、第二步:BIOS 查找引导设备

2.2.1 Legacy BIOS & Legacy GRUB

对于 Legacy BIOS 来说,一般而言只能引导 MBR (Main Boot Record)分区表,在 MBR 分区中,磁盘前 512 字节(即0柱面,0磁头,1扇区)记录着引导记录和分区表信息,数据结构如下。

  • MBR:主引导记录,可以安装开机管理程序的地方,占 446 字节
  • DPT:磁盘分区表,占 64 字节
  • 结束标志:55 AA,占 2 字节

GRUB 安装过程(grub-install /dev/sda):

  • /boot/grub/stage1 的前 446 字节写入磁盘的 1 扇区
  • /boot/grub/e2fs_stage1_5 从磁盘的 2 扇区开始写入,共 13380 字节,占 27 个扇区
  • 生成 /boot/grub/grub.conf

补充 Linux 分区知识:

  • 在 MBR 分区表中,Linux 会把磁盘的前 2047 个扇区的空间预留出来,也就是说第一个分区是从 2048 扇区开始的
  • 第一个扇区写入 MBR + DPT
  • 2 ~ 2047 个扇区,预留给 GRUB 等引导器写入引导代码

因此,BIOS 读取了第一个扇区的数据之后,就知道了如何引导系统了。

  • 读取第一个扇区,作用只有一个,就是将磁盘第二个扇区的内容加载的到内存
  • 第二个扇区的作用就是加载磁盘的第三个扇区到第N个扇区到内存,N取几,取决于文件系统的支撑代码的大小
  • 此时,已经加载了文件系统的驱动了,读取 /boot/grub/stage2/boot/grub/grub.conf 等文件,将引导菜单展示到屏幕
2.2.2 Legacy BIOS & GRUB2

前面说到,GRUB2 是 GRUB 的增强版,现在各发行版都已经迁移至 GRUB2 了。因此,了解 GRUB2 也是必须的了。

GRUB2 相比 GRUB 具有如下一些新特征:

  • 无 stage1 stage1.5 stage2
  • 配置文件采用新语法,支持脚本,加入新的命令,配置文件名为 grub.cfg
  • 配置文件 grub.cfg不可写,由 grub2-mkconfig 自动产生,由 update2-grub 维护。
  • 分区号不再从 0开始,而是从 1开始
  • 支持更多到文件系统,如:ext4、hfs、ntfs,并可以直接从 lvm和raid中读取文件/li>
  • grub2有更可靠的方法在磁盘上有多系统时发现文件和目标内核,可以用命令发现系统设备号或者UUID。
  • 引入了设备模块,使得 core 镜像保持更小到尺寸
  • 在启动时没有选择菜单的话,按住shift即可强制显示菜单

GRUB2 安装过程(grub2-install,grub2-mkconfig):

  • 安装 GRUB 文件到 /boot/grub2
  • 复制 /usr/lib/grub/i386-pc/ 目录下的.mod.lst.img/boot/grub 目录下
  • /boot/grub2/i386-pc/boot.img 相当与 GRUB 的 stage1 被写入 MBR
  • grub-mkimage 程序将 /usr/lib/grub/i386-pc/kernel.img 和一些模块动态编译生成 /boot/grub2/i386-pc/core.img,它包含了文件系统等重要驱动,并写入到磁盘的第二个扇区,相当于 GRUB 的 stage1.5
  • grub2-mkconfig 生成 /boot/grub2/grub.cfg /boot/grub2/device.map 等文件

引导过程与 GRUB 同理:

  • 读取第一个扇区,作用只有一个,就是将磁盘第二个扇区的内容加载的到内存
  • 第二个扇区的作用就是加载磁盘的第三个扇区到第N个扇区到内存,N取几,取决于 core.img 的大小
  • 此时,已经加载了文件系统的驱动了,读取 /boot/grub/stage2/boot/grub/grub.conf 等文件,将引导菜单展示到屏幕
2.2.3 UEFI BIOS 的启动过程

UEFI 全称“统一的可扩展固件接口”(Unified Extensible Firmware Interface),目前已取代传统 BIOS 成为事实上的标准了。在个人PC市场,尤其是笔记本市场,已经是清一色的使用了 UEFI 固件。

UEFI 与 Legacy BIOS 在引导上是完全不同的两个东西,上面已经介绍了 Legacy BIOS 是如何引导 GRUB 运行操作系统的,这一小节我们来了解一下 UEFI 是如何引导 GRUB 的。

UEFI 固件内置了 FAT 格式的驱动程序,默认情况下 UEFI 会搜索所有磁盘的 FAT 格式分区,并读取 FAT 分区的 /EFI/BOOT/BOOTx64.EFI 文件,此文件就是 UEFI 的系统引导文件,UEFI 在 BOOTx64.EFI 的指引下引导操作系统。

当然了,UEFI 也允许操作系统厂家不遵守这样的目录结构。操作系统厂家可以根据自己的需求来组织 EFI 文件,但是需要将可引导写到 UEFI 固件里。因为是以配置文件的方式保存至 UEFI 的可写 ROM 里的,因此恢复出厂或人为删除都会导致引导项丢失。

以 CentOS 7 为例,安装完系统后,会在 UEFI 引导项新增一条记录“CentOS”,CentOS 指向 /EFI/BOOT/centos/shimx64.efi,shimx64.efi 指挥着 UEFI 读取 grubx64.efi,grubx64.efi 读取相关配置文件,显示 CentOS 的启动菜单。总结一下,CentOS 7 的启动顺序就如下图所示。

CentOS7引导流程.png

3、操作系统初始化流程

上面花了很大篇幅去讲解计算机是如何引导操作系统的,目的是给大家补充计算机的一些了冷门知识。接下来讲解操作系统是如何进行初始化工作的。以 CentOS 6 为例讲解。

3.1、内核初始化

在 GRUB 菜单中,按 e 键进去可以看到 GRUB 的引导参数:

root (hd0,0)
kernel /vmlinuz-2.6.32-696.20.1.el6.x86_64
initrd /initramfs-2.6.32-696.20.1.el6.x86_64.img
  • root (hd0,0) 第一个磁盘的第一个分区
  • kernel 内核文件
  • initrd 为内核提供额外文件的 ramdisk,是一个简装版的根文件系统,解开之后,可以看到完整的 Linux 目录结构。其的作用是为内核提供必须的驱动、切换新根等

附解开 vmlinux 和 initramfs 的命令:

# 解开 vmlinux
od -t x1 -A d ../vmlinuz-2.6.32-696.20.1.el6.x86_64 | grep "1f 8b 08"
# 输出结果:0014432 48 8d 83 60 e3 40 00 ff e0 1f 8b 08 00 c3 6a 6b
# 我们要拿 14432 这个数值,加 9 得到最终的位置 = 14441
dd if=vmlinuz-2.6.32-696.20.1.el6.x86_64 bs=1 skip=14441 | zcat > vmlinux
# 得到最终的可执行文件 vmlinux

# 解开 initramfs
gunzip -c /boot/initramfs-2.6.32-696.20.1.el6.x86_64.img | cpio -id

补充细节:

  • initramfs 会被 kernel 加载至内存
  • 接着执行 initramfs 的 init 脚本
  • init 脚本做的主要的事情就是做一些初始化工作,然后执行 switch_root 命令
  • switch_root 命令的主要作用是把 initramfs 的内容全部删除以释放内存,挂载根并切换根,执行 /sbin/init

3.2、init 运行过程

  • /etc/init/rcS.conf

    • exec /etc/rc.d/rc.sysinit

      • 打印 Welcome to SentOS ...
      • 初始化硬件
      • 启动 udev
      • 设置主机名
      • 配置网络参数
      • 挂载 proc、sys
      • 配置内核参数
      • 挂载 /etc/fstab 定义的挂载点
      • ...
    • 确认运行级别 /etc/inittab

      • exec telinit $runlevel
  • /etc/init/rc.conf

    • exec /etc/rc.d/rc $RUNLEVEL

      • /etc/profile.d/lang.sh 设置语言环境
      • 执行 /etc/rc$runlevel.d/ 下以 K 开头的脚本文件
      • 执行 /etc/rc$runlevel.d/ 下以 S 开头的脚本文件
  • /etc/rc.d/rc.local
  • /etc/init/start-ttys.conf

    • 启动tty1-tty6设备

3.3、用户登录

  • /sbin/mingetty 运行mingetty程序,出现字符登录界面

    • /etc/issue 在登录界面上显示发行版信息
    • exec("/bin/login",...) 运行/bin/login程序,验证用户名和口令

      • /etc/passwd 读取passwd文件核对用户名和口令
      • 登录成功,切换到工作目录
      • 初始化环境变量$HOME,$PATH
      • /etc/motd 显示这个文件的内容
      • 检查新邮件
      • exec("/bin/bash",...) 运行bash程序

        • /etc/profile 执行这个脚本中

          • /etc/profile.d/*.sh 执行这些脚本
          • 执行.bash_profile

            • 执行~/.bashrc

              • 执行/etc/bashrc

4、补充 CentOS 7 的系统初始化流程

4.1、systemd 运行过程

操作系统在 POST 到加载系统初始化程序的过程和 CentOS 6 基本一致,这里就不再赘述了,主要是补充一下 systemd 初始化程序的执行流程。

systemd 程序执行后,首先会执行默认目标 default.target (/etc/systemd/system/default.target),这个文件是个软链接,一般默认会指向 /lib/systemd/system/multi-user.target。

.target 的含义,我理解为是一组 Unit 的集合,systemd 会执行 /etc/systemd/system/ 和 /usr/lib/systemd/system/ 下 同名 + .wants 路径下的所有单元。

systemd 会自动处理依赖关系,我们通过查看 default.target 文件得知其依赖路径大致可简化为:

default.target(multi-user.target) -> basic.target -> sysinit.target -> local-fs.target swap.target

那么启动顺序就是反过来的:

local-fs.target swap.target -> sysinit.target -> basic.target -> default.target(multi-user.target)

4.2、systemd 如何兼容 sysv 启动脚本

systemd 中依然保留了兼容 sysv 风格的启动脚本特性,使用传统的 chkconfig 命令可以查看并改变服务的开机启动。

当你执行 chkconfig --add xxx 时,系统会在 /run/systemd/generator.late 路径生成一个 xxx.service 文件,以此来兼容 sysv 启动脚本。

5、后记

以上就是 Linux 启动的全过程了,对于其他操作系统如 Windows 系统来说,其引导部分原理是一样的,只是说引导菜单的展示使用了不同的技术罢了。后半部分的系统初始化流程则是各操作系统的实现都不一样,在 Linux 界,其主要分为 init 和 systemd,其代表就是 CentOS 6 和 CentOS 7 。好了,到目前为止,Linux 的启动就完成了。

标签: none

添加新评论