鸟哥的linux私房菜——第十九章学习(Linux的开机流程分析)

 

第十九章学习(Linux的开机流程分析)

1.1)、开机流程

简单来说,系统开机的经过可以汇整成下面的流程的:

1. 载入 BIOS 的硬件信息与进行自我测试,并依据设置取得第一个可开机的设备;

2. 读取并执行第一个开机设备内 MBR 的 boot Loader (亦即是 grub2, spfdisk 等程序);

3. 依据 boot loader 的设置载入 Kernel ,Kernel 会开始侦测硬件与载入驱动程序;

4. 在硬件驱动成功后,Kernel 会主动调用 systemd 程序,并以 default.target 流程开机;

    • systemd 执行 sysinit.target 初始化系统及 basic.target 准备操作系统;
    • systemd 启动 multi-user.target 下的本机与服务器服务;
    • systemd 执行 multi-user.target 下的 /etc/rc.d/rc.local 文件;
    • systemd 执行 multi-user.target 下的 getty.target 及登陆服务;
    • systemd 执行 graphical 需要的服务。

 

2.1)、开机流程第一步:BIOS,boot loader和kernel载入

  • 名词说明:
    • BIOS:不论传统 BIOS 还是 UEFI BIOS 都会被简称为 BIOS(Basic Input Output System);
    • MBR:虽然分区表有传统 MBR 以及新式 GPT,不过 GPT 也有保留一块相容 MBR 的区块,因此,下面的说明在安装 boot loader 的部份, 鸟哥还是简称为 MBR 喔!总之,MBR 就代表该磁盘的最前面可安装 boot loader 的那个区块就对了!(Master Boot Record) 主要开机记录区。
  • BIOS, 开机自我测试与 MBR/GPT

POST:开机自我测试 (Power-on Self Test)

我们的系统软件大多放置到硬盘中,所以 BIOS 会指定开机的设备好让我们可以读取磁盘中的操作系统核心文件。但由于不同的操作系统的文件系统格式不相同,因此我们必须要以一个开机管理程序来处理核心文件载入 (load) 的问题,因此这个开机管理程序就被称为 Boot Loader 了。

那这个 Boot Loader 程序安装在哪里呢?就在开机设备的第一个扇区 (sector内,也就是我们一直谈到的 MBR(Master Boot Record, 主要开机记录区)。

 

系统载入BIOS --> 取得主机各项硬件信息 --> 开机自我测试(POST)--> 硬件侦测初始化 --> 定义可开机的设备顺序 --> 开机设备的数据读取(BIOS指定设备来读取磁盘中的操作系统核心文件),通过开机管理程序(Boot Loader)来载入(load)核心文件,而Boot Loader安装在开机设备的第一个扇区内,即MBR。

 

2.2)、开机流程第二步:读取 MBR内的 loader并执行

每个操作系统的 loader 都不相同,那么BIOS 又是如何读取 MBR内的 loader 呢?

其实 BIOS 是通过硬件的 INT 13 中断功能来读取 MBR 的,也就是说,只要 BIOS 能够侦测的到你的磁盘(不论该磁盘是 SATA 还是 SAS 接口),那他就有办法通过 INT 13 这条信道来读取该磁盘的第一个扇区内的 MBR 软件,这样 boot loader 也就能够被执行啰!

 

  •  Boot Loader 的功能

那问题就来啦,既然 (1)必须要使用自己的 loader 才能够载入属于自己的操作系统核心,而 (2)系统的 MBR 只有一个,那怎么会有办法同时在一部主机上面安装 Windows 与 Linux 呢?

这是因为安装多重操作系统时,MBR 常常会被不同的操作系统的 boot loader 所覆盖。

另外,这也是为什么安装双系统时,必须嘚先安装Windows再安装Linux,而不能反过来。

在 Linux 系统安装时,你可以选择将 boot loader 安装到 MBR 去,也可以选择不安装。

在Windows 安装时,他默认会主动的将 MBR 与 boot sector 都装上一份 boot loader

 

2.3)、开机流程第三步:boot loader载入内核,Kernel侦测硬件与载入驱动程序

  • boot loader 主要的功能如下:
    • 提供菜单:使用者可以选择不同的开机项目,这也是多重开机的重要功能!
    • 载入核心文件:直接指向可开机的程序区段来开始操作系统;
    • 转交其他loader:将开机管理功能转交给其他 loader 负责。

不过 Windows 的 loader 默认不具有控制权转交的功能,因此你不能使用 Windows 的 loader 来载入 Linux 的 loader 。

而最终 boot loader 的功能就是“载入 kernel 文件”。

鸟哥的linux私房菜——第十九章学习(Linux的开机流程分析)

BIOS 与 boot loader 及核心载入流程示意图

  • 载入核心侦测硬件与 init RAM fs 的功能

Linux 核心是可以通过动态载入核心模块的 (就请想成驱动程序即可),些核心模块就放置在 /lib/modules/ 目录内。

由于模块放置到磁盘根目录内 (要记得 /lib 不可以与 / 分别放在不同的 partition !), 因此在开机的过程中核心必须要挂载根目录,这样才能够读取核心模块提供载入驱动程序的功能。

 

一般滴,非必要的功能且可以编译成为模块的核心功能,目前的 Linux distributions 都会将他编译成为模块,如USB,SATA等。

现在来思考一种情况,假设你的 linux 是安装在 SATA 磁盘上面的,你可以通过 BIOS 的 INT 13 取得 boot loader 与 kernel 文件来开机,然后 kernel 会开始接管系统并且侦测硬件及尝试挂载根目录来取得额外的驱动程序。

问题是核心根本不认识 SATA 磁盘,所以需要载入 SATA 磁盘的驱动程序, 否则根本就无法挂载根目录。但是 SATA 的驱动程序在/lib/modules 内,你根本无法挂载根目录又怎么读取到 /lib/modules/ 内的驱动程序?

我们可以采用虚拟文件系统来解决该问题:

虚拟文件系统 (Initial RAM Disk 或 Initial RAM Filesystem) 一般使用的文件名为 /boot/initrd 或 /boot/initramfs ,这个文件的特色是,他也能够通过 boot loader 来载入到内存中,然后这个文件会被解压缩并且在内存当中仿真成一个根目录, 且此仿真在内存当中的文件系统能够提供一支可执行的程序,通过该程序来载入开机过程中所最需要的核心模块, 通常这些模块就是 USB, RAID, LVM, SCSI 等文件系统与磁盘接口的驱动程序啦!等载入完成后, 会帮助核心重新调用 systemd 来开始后续的正常开机流程(见上图)。

总结:如上图所示,boot loader 可以载入 kernel 与 initramfs ,然后在内存中让 initramfs 解压缩成为根目录, kernel 就能够借此载入适当的驱动程序,最终释放虚拟文件系统,并挂载实际的根目录文件系统,就能够开始后续的正常开机流程。

 

在核心载入完毕、进行完硬件侦测与驱动程序载入后,此时你的主机硬件应该已经准备就绪了 (ready) 。

此时核心会主动的调用第一支程序,那就是 systemd。

systemd 最主要的功能就是准备软件执行的环境,包括系统的主机名称、网络设置、语系处理、文件系统格式及其他服务的启动等。 而所有的动作都会通过 systemd的默认启动服务集合,亦即是 /etc/systemd/system/default.target 来规划。

 

  • 第一支程序systemd及使用default.target进入开机程序分析
    • 常见的操作环境 target 与相容于 runlevel 的等级

可以作为默认的操作环境 (default.target) 的主要项目有: multi-user.target 以及 graphical.target 这两个。

过去的 systemV 使用的是一个称为 runlevel (执行等级) 的概念来启动系统的,systemd 为了相容于旧式的 systemV 操作行为,所以也将 runlevel 与操作环境做个结合。

鸟哥的linux私房菜——第十九章学习(Linux的开机流程分析)

 

 

 

切换执行等级可以使用“ init 3 ”转成文字界面,“ init 5 ”转成图形界面。

当我们取得了 /etc/systemd/system/default.target 这一个默认操作界面的设置之后,它会链接到 /usr/lib/systemd/system/ 这个目录下去取得 multi-user.target 或 graphical.target 这两个其中的一个。

假设我们是使用 graphical.target,接着下来 systemd 会去找两个地方的设置, 就是如下的目录:

    •   /etc/systemd/system/graphical.target.wants/:使用者设置载入的 unit;
    •   /usr/lib/systemd/system/graphical.target.wants/:系统默认载入的 unit;

然后再由 /usr/lib/systemd/system/graphical.target 这个配置文件内发现如下的数据:

[root@study ~]# cat /usr/lib/systemd/system/graphical.target
[Unit]
Description=Graphical Interface
Documentation=man:systemd.special(7)
Requires=multi-user.target
After=multi-user.target
Conflicts=rescue.target
Wants=display-manager.service
AllowIsolate=yes
[Install]
Alias=default.target

这表示 graphical.target 必须要完成 multi-user.target 之后才能够进行,而进行完 graphical.target 之后,还得要启动 displaymanager.service 才行。

 

注:要知道系统的服务启用的流程,最简单的方法就是“ systemctl list-dependencies graphical.target ”这个指令!只是,如果你想要知道背后的配置文件意义, 那就是分别去找出 /etc 与 /usr/lib 下面的 graphical.target.wants/ 目录下的数据就对了!当然,配置文件脚本里面的Requires 这个设置值所代表的服务, 也是需要是先载入。

 

  • systemd执行sysinit.target初始化系统、basic.target准备系统

在这个阶段完成之后,你的系统已经可以顺利的运行!就差一堆你需要的登陆服务、网络服务、本机认证服务等等的 service 类别啰!于是就可以进入下个服务启动的阶段了。

 

一般来说服务的启动脚本设置都是放在下面的目录内:

/usr/lib/systemd/system (系统默认的服务启动脚本设置)

/etc/systemd/system (管理员自己开发与设置的脚本设置)

 

能不能提供适当的登陆服务也是 multi-user.target 下面的内容!包括 systemd-logind.service, systemd-user-sessions.service 等服务。

由于服务都是同步运行,不一定哪个服务先启动完毕。如果 getty 服务先启动完毕时,你会发现到有可用的终端机尝试让你登陆系统了。 问题是,如果 systemd-logind.service 或 systemd-user-sessions.service 服务尚未执行完毕的话,那么你还是无法登陆系统的。

 

到此为止,systemd 就已经完整的处理完毕,你可以使用图形界面或文字界面的方式来登陆系统,系统也顺利的开机完毕, 也能够将你写入到 /etc/rc.d/rc.local 的脚本实际执行一次啰。

 

3.1)、核心与核心模块

谈完了整个开机的流程,您应该会知道,在整个开机的过程当中,是否能够成功的驱动我们主机的硬件配备, 是核心 (kernel) 的工作!而核心一般都是压缩文件,因此在使用核心之前,就得要将他解压缩后,才能载入内存当中。

目前的核心都是具有“可读取模块化驱动程序”的功能, 亦即是所谓的“ modules (模块化)”的功能啦!所谓的模块化可以将他想成是一个“外挂程序”。

那么核心与核心模块放在哪?

    •   核心: /boot/vmlinuz 或 /boot/vmlinuz-version;
    •   核心解压缩所需 RAM Disk: /boot/initramfs (/boot/initramfs-version);
    •   核心模块: /lib/modules/version/kernel 或 /lib/modules/$(uname -r)/kernel;
    •   核心源代码: /usr/src/linux 或 /usr/src/kernels/ (要安装才会有,默认不安装)

如果该核心被顺利的载入系统当中了,那么就会有几个信息纪录下来:

    •   核心版本: /proc/version
    •   系统核心功能: /proc/sys/kernel/

问题来啦,如果我有个新的硬件,偏偏我的操作系统不支持,该怎么办?很简单啊!

    •   重新编译核心,并加入最新的硬件驱动程序源代码;
    •   将该硬件的驱动程序编译成为模块,在开机时载入该模块。
  • 模块的相依性

可以使用lsmod来查看模块之间的相依性,另外还可以使用modinfo [module_name]来查看某模块的具体信息。

  • 模块的载入与移除

使用modprobe [module_name]:因为该指令会主动去搜索modeules.dep的内容,先克服了模块的相依性后,才决定需要载入的模块有哪些。该指令并不需要知道模块的完整路径名就可加载。

此外,还有insmod来加载,但是得需要知道完整的路径名;

删除命令rmmod也是,也需要知道完整的路径名。

3.2)Boot Loader:Grub2

没有 boot loader 的话,那么 kernel 根本就没有办法被系统载入。

  • boot loader 的两个stage:

为什么要分两个stage?

因为在BIOS读完信息后,会去第一个开机设备的MBR读取boot Loader,而MBR是整个硬盘的第一个sector内的一个区块,最大446Bytes,放不下所有的额程序码和数据。

 

stage1:执行boot loader主程序

该主程序必须要被安装在开机区,亦即是 MBR 或者是 boot sector,因为 MBR实在太小了,所以,MBR 或 boot sector 通常仅安装 boot loader 的最小主程序, 并没有安装 loader 的相关配置文件。

stage2:主程序载入配置文件

包括文件系统定义与主要配置文件 grub.cfg,一般来说配置文件都在/boot下面。

 

  • Grub2的配置文件:/boot/grub2/grub.cfg

Grub2的优点:

    • 认识与支持较多的文件系统;
    • 开机时,可自行编辑与修改开机设置项目;
    • 可动态搜索配置文件,修改完后不需要重新安装,下次开机即生效。

上面第三点其实也是 Stage 1, Stage 2 分别安装在 MBR (主程序) 与文件系统当中 (配置文件与定义文件) 的原因。

  •  initramfs 的重要性

initramfs 可以将 /lib/modules/.... 内的“开机过程当中一定需要的模块”包成一个文件 (文件名就是 initramfs), 然后在开机时通过主机的INT 13 硬件功能将该文件读出来解压缩,并且 initramfs 在内存内会仿真成为根目录, 由于此虚拟文件系统 (Initial RAM Disk) 主要包含磁盘与文件系统的模块,因此我们的核心最后就能够认识实际的磁盘, 那就能够进行实际根目录的挂载。所以说:“initramfs 内所包含的模块大多是与开机过程有关,而主要以文件系统及硬盘模块 (如 usb, SCSI 等) 为主”。

 

【重点回顾】

① Linux 不可随意关机,否则容易造成文件系统错乱或者是其他无法开机的问题;

② 开机流程主要是:BIOS、MBR、Loader、kernel+initramfs、systemd 等流程;

③ Loader 具有提供菜单、载入核心文件、转交控制权给其他 loader 等功能。

④ boot loader 可以安装在 MBR 或者是每个分区的 boot sector 区域中;

⑤ initramfs 可以提供核心在开机过程中所需要的最重要的模块,通常与磁盘及文件系统有关的模块;

⑥ systemd 的配置文件为主要来自 /etc/systemd/system/default.target 项目;

⑦ 额外的设备与模块对应,可写入 /etc/modprobe.d/*.conf 中;

⑧ 核心模块的管理可使用 lsmod, modinfo, rmmod, insmod, modprobe 等指令;

⑨ modprobe 主要参考 /lib/modules/$(uanem -r)/modules.dep 的设置来载入与卸载核心模块;

⑩ grub2 的配置文件与相关文件系统定义文件大多放置于 /boot/grub2 目录中,配置文件名为 grub.cfg;

⑪ grub2 对磁盘的代号设置与 Linux 不同,主要通过侦测的顺序来给予设置。如 (hd0) 及 (hd0,1) 等。

⑫ grub.cfg 内每个菜单与 menuentry 有关,而直接指定核心开机时,至少需要 linux16 及 initrd16 两个项目;

⑬ grub.cfg 内设置 loader 控制权移交时,最重要者为 chainloader +1 这个项目。

⑭ 若想要重建 initramfs ,可使用 dracut 或 mkinitrd 处理;

⑮ 重新安装 grub2 到 MBR 或 boot sector 时,可以利用 grub2-install 来处理。

⑯ 若想要进入救援模式,可于开机菜单过程中,在 linux16 的项目后面加入“ rd.break ”或“ init=/bin/bash ”等方式来进入救援模式。

⑰ 我们可以对 grub2 的个别菜单给予不同的密码。

 

 

 

Over......

上一篇:Systemd基础篇:systemd vs SysVinit


下一篇:This file is managed by systemd-resolved(8). Do not edi.Systemd-networkd:如何在dhcp发现的命名服务器前添加静态命名服务器表项