Linux GRUB引导与启动过程详解
1. 数据重复区域与分区表位置
在输出中,地址 0000020 到 0000120 之间存在第二个数据重复区域。由于该区域与实际的引导记录不同,且在文件中全为零,我们可以推断这是实际引导记录中分区表的位置。
此外,有一个实用工具
strings
可用于查看文件中的 ASCII 文本字符串:
[root@studentvm1 ~]# strings /boot/grub2/i386-pc/boot.img
ZRr=
`|f
\|f1
GRUB
Geom
Hard Disk
Read
Error
Floppy
这个工具比从大量随机 ASCII 字符中筛选有意义的字符串更容易定位实际文本。
GRUB 引导记录安装在硬盘或其他可引导介质的第一个扇区,以
boot.img
文件为源。分区表则叠加在引导记录的指定位置。
2. GRUB 阶段 1.5
GRUB 的阶段 1.5 必须位于引导记录与 UEFI 分区数据以及磁盘驱动器上第一个分区之间的空间。由于技术和兼容性原因,这个空间历史上一直未被使用,有时被称为“引导轨道”或“MBR 间隙”。
硬盘的第一个分区从扇区 63 开始,MBR 在扇区 0,因此有 62 个 512 字节的扇区(共 31,744 字节)可用于存储 GRUB 阶段 1.5,该阶段以
core.img
文件形式分发。目前,
core.img
文件大小为 28,535 字节,所以 MBR 和第一个磁盘分区之间有足够的空间来存储它。
2.1 实验:验证 GRUB 阶段 1.5
包含 GRUB 阶段 1.5 的文件存储在
/boot/grub2/i386-pc/core.img
。可以通过比较该文件中的代码与引导驱动器 MBR 间隙中存储的代码来验证:
[root@studentvm1 ~]# dd if=/dev/sda bs=512 count=1 skip=1 | od -a -
1+0 records in
1+0 records out
512 bytes copied, 0.000132697 s, 3.9 MB/s
0000000 E F I sp P A R T nul nul soh nul \ nul nul nul
0000020 ( ` * so nul nul nul nul soh nul nul nul nul nul nul nul
0000040 del del del bel nul nul nul nul " nul nul nul nul nul nul nul
0000060 ^ del del bel nul nul nul nul | ht @ ack _ sp nl F
0000100 dc1 ff c ? 1 > so etx stx nul nul nul nul nul nul nul
0000120 nul nul nul nul nul nul nul nul ack ~ J $ nul nul nul nul
0000140 nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul
*
0001000
[root@studentvm1 ~]# dd if=/boot/grub2/i386-pc/core.img bs=512 count=1 | od -a -
1+0 records in
1+0 records out
512 bytes copied, 5.1455e-05 s, 10.0 MB/s
0000000 R V > esc soh h 9 soh ^ ? t soh f vt - etx
0000020 } bs nul si eot b nul nul | del nul t F f vt gs
0000040 f vt M eot f 1 @ 0 del 9 E bs del etx vt E
0000060 bs ) E bs f soh enq f etx U eot nul G eot dle nul
0000100 ht D stx f ht \ bs f ht L ff G D ack nul p
0000120 P G D eot nul nul 4 B M dc3 si stx / nul ; nul
0000140 p k f f vt E eot f ht @ si enq etb nul f vt
0000160 enq f 1 R f w 4 bs T nl f 1 R f w t
0000200 eot bs T vt ht D ff ; D bs } y vt eot * D
0000220 nl 9 E bs del etx vt E bs ) E bs f soh enq f
0000240 etx U eot nul nl T cr @ b ack nl L nl ~ A bs
0000260 Q nl l ff Z R nl t vt P ; nul p so C 1
0000300 [ 4 stx M dc3 r F ff C so E nl X A ` enq
0000320 soh E nl ` rs A ` etx ht A 1 del 1 v so [
0000340 | s % us > # soh h W nul a etx } bs nul si
0000360 enq $ del etx o ff i syn del > % soh h B nul Z
0000400 j nul stx nul nul > ( soh h 6 nul k ack > - soh
0000420 h . nul > 2 soh h ( nul k ~ l o a d i
0000440 n g nul . nul cr nl nul G e o m nul R e a
0000460 d nul sp E r r o r nul ; soh nul 4 so M dle
0000500 F nl eot < nul u r C nul nul nul nul nul nul nul nul
0000520 nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul
*
0000760 nul nul nul nul stx nul nul nul nul nul nul nul ? nul sp bs
00001000
每个文件的第一个扇区就足以进行验证,但你也可以探索更多代码。虽然有工具可用于比较文件与硬盘上 GRUB 阶段 1.5 中的数据,但显然这两个扇区的数据是相同的。
由于阶段 1.5 可以容纳比阶段 1 更多的代码,它可以包含一些常见的文件系统驱动程序,如标准的 EXT、XFS 以及其他非 Linux 文件系统(如 FAT 和 NTFS)。GRUB2 的
core.img
比旧的 GRUB1 阶段 1.5 更复杂、功能更强大。这意味着 GRUB2 的阶段 2 可以位于标准的 EXT 文件系统上,但不能位于逻辑卷上,因为它需要在文件系统驱动程序加载之前从可引导卷的特定位置读取。
需要注意的是,
/boot
目录必须位于 GRUB 支持的文件系统(如 EXT4)上。阶段 1.5 的功能是使用必要的文件系统驱动程序开始执行,以定位
/boot
文件系统中的阶段 2 文件并加载所需的驱动程序。
3. GRUB 阶段 2
GRUB 阶段 2 的所有文件位于
/boot/grub2
目录及其子目录中。GRUB2 不像阶段 1 和 2 那样有图像文件,而是由这些文件和运行时内核模块组成,这些模块根据需要从
/boot/grub2
目录及其子目录中加载。一些 Linux 发行版可能将这些文件存储在
/boot/grub
目录中。
GRUB 阶段 2 的功能是定位并将 Linux 内核加载到 RAM 中,然后将计算机的控制权交给内核。内核及其关联文件位于
/boot
目录中。内核文件的名称都以
vmlinuz
开头。
3.1 实验:查看 Linux 内核
可以列出
/boot
目录的内容,查看系统上当前安装的内核:
[root@studentvm1 ~]# ll /boot
total 275508
-rw-r--r--. 1 root root 251528 Nov 4 14:55 config-6.0.7-301.fc37.x86_64
-rw-r--r--. 1 root root 253534 Jan 14 12:12 config-6.1.6-200.fc37.x86_64
-rw-r--r-- 1 root root 253512 Jan 18 12:29 config-6.1.7-200.fc37.x86_64
drwx------ 4 root root 4096 Dec 31 1969 efi
drwx------. 5 root root 4096 Jan 29 08:28 grub2
-rw-------. 1 root root 105160151 Jan 17 07:39 initramfs-0-rescue-
d1fbbe41229942289e5ed31a256200fb.img
-rw-------. 1 root root 36685746 Jan 17 07:40 initramfs-6.0.7-301.fc37.x86_64.img
-rw-------. 1 root root 34616617 Jan 17 21:33 initramfs-6.1.6-200.fc37.x86_64.img
-rw------- 1 root root 34617482 Jan 24 08:29 initramfs-6.1.7-200.fc37.x86_64.img
drwxr-xr-x. 3 root root 4096 Jan 17 07:36 loader
drwx------. 2 root root 16384 Jan 17 07:29 lost+found
lrwxrwxrwx. 1 root root 45 Jan 17 07:36 symvers-6.0.7-301.fc37.x86_64.
gz -> /lib/modules/6.0.7-301.fc37.x86_64/symvers.gz
lrwxrwxrwx. 1 root root 45 Jan 17 21:32 symvers-6.1.6-200.fc37.x86_64.
gz -> /lib/modules/6.1.6-200.fc37.x86_64/symvers.gz
lrwxrwxrwx 1 root root 45 Jan 24 08:28 symvers-6.1.7-200.fc37.x86_64.
gz -> /lib/modules/6.1.7-200.fc37.x86_64/symvers.gz
-rw-------. 1 root root 7252122 Nov 4 14:55 System.map-6.0.7-301.fc37.x86_64
-rw-------. 1 root root 5984440 Jan 14 12:12 System.map-6.1.6-200.fc37.x86_64
-rw------- 1 root root 5988800 Jan 18 12:29 System.map-6.1.7-200.fc37.x86_64
-rwxr-xr-x. 1 root root 12727016 Jan 17 07:37 vmlinuz-0-rescue-
d1fbbe41229942289e5ed31a256200fb
-rwxr-xr-x. 1 root root 12727016 Nov 4 14:55 vmlinuz-6.0.7-301.fc37.x86_64
-rwxr-xr-x. 1 root root 12761928 Jan 14 12:12 vmlinuz-6.1.6-200.fc37.x86_64
-rwxr-xr-x 1 root root 12781480 Jan 18 12:29 vmlinuz-6.1.7-200.fc37.x86_64
列表底部有四个内核文件,名称以
vmlinuz
开头,但名称中的 “vm” 与 “虚拟机” 无关。
这些内核的支持文件也在列表中,包括救援内核。
System.map
文件是符号表,用于映射变量和函数等符号的物理地址。
initramfs
文件在 Linux 引导过程早期使用,此时内核和文件系统驱动程序尚未加载,文件系统也未挂载。
3.2 GRUB 引导菜单
GRUB 引导菜单允许选择不同的内核。默认内核始终是更新过程中安装的最新内核,它将在五秒的短超时后自动启动。
- 如果按下上下箭头键,倒计时停止,高亮条移动到另一个内核,按下 Enter 键即可启动所选内核。
- 如果按下除上下箭头键、“E” 或 “C” 键以外的几乎任何键,倒计时停止并等待更多输入。此时,你可以使用箭头键选择要启动的内核,然后按下 Enter 键启动。
GRUB 阶段 2 将所选内核加载到内存中,并将计算机的控制权交给内核。
救援启动选项是解决启动问题(如阻止 Linux 系统完成启动过程的问题)的最后手段。当启动过程中出现某些类型的错误时,GRUB 将自动回退到从救援映像启动。
4. 配置 GRUB
GRUB 使用
/boot/grub2/grub.cfg
进行配置,但我们不直接修改该文件,因为内核更新到新版本时它可能会被覆盖。相反,我们修改
/etc/default/grub
文件。
4.1 实验:配置 GRUB
首先查看
/etc/default/grub
文件的未修改版本:
[root@studentvm1 ~]# cd /etc/default ; cat grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="resume=/dev/mapper/fedora_studentvm1-swap rd.lvm.
lv=fedora_studentvm1/root rd.lvm.lv=fedora_studentvm1/swap rd.lvm.lv=fedora_
studentvm1/usr rhgb quiet"
GRUB_DISABLE_RECOVERY="true"
通常可以修改以下三个参数:
-
GRUB_TIMEOUT
:将 GRUB 菜单倒计时的秒数从 5 改为 10,以便有更多时间响应 GRUB 菜单。
-
GRUB_DISABLE_RECOVERY
:从 “true” 改为 “false”,原本是为每个安装的内核创建救援启动选项,但从 Fedora 30 开始不再起作用。
-
GRUB_CMDLINE_LINUX
:删除最后两个参数 “rhgb” 和 “quiet”。“rhgb” 参数表示 Red Hat 图形化启动,会在核初始化期间显示 Fedora 图标动画,而不是显示启动消息;“quiet” 参数会阻止显示记录启动进度和可能出现的错误的启动消息。系统管理员需要能够看到这些消息,以便在启动过程中出现问题时找到原因。
修改后的
grub
文件如下:
[root@studentvm1 default]# cat grub
GRUB_TIMEOUT=10
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="resume=/dev/mapper/fedora_studentvm1-swap rd.lvm.lv=
fedora_studentvm1/root rd.lvm.lv=fedora_studentvm1/swap rd.lvm.lv=fedora_
studentvm1/usr"
GRUB_DISABLE_RECOVERY="true"
检查
/boot/grub2/grub.cfg
文件的当前时间戳和内容,查看这些特定变量。
运行以下命令更新
/boot/grub2/grub.cfg
配置文件:
[root@studentvm1 default]# grub2-mkconfig > /boot/grub2/grub.cfg
Generating grub configuration file ...
Adding boot menu entry for UEFI Firmware Settings ...
done
再次检查
/boot/grub2/grub.cfg
的时间戳和内容,应该会反映出这些更改。可以使用
grep
命令验证更改是否生效。
也可以使用带有
-o
参数的替代命令指定输出文件:
grub2-mkconfig -o /boot/grub2/grub.cfg
两种形式的命令都可以工作,结果相同。
5. 完成 GRUB 引导
加载 GRUB 阶段 2 后,GRUB 菜单会显示,用户可以选择非默认的可选内核。用户也可以让超时时间到期或在默认选择上按下 Enter 键,这两种方式都会启动默认内核。
GRUB 阶段 2 定位并加载所选内核,然后将控制权交给内核。
6. Linux 内核
所有 Linux 内核都采用自解压、压缩格式以节省空间。内核位于
/boot
目录中,同时还有初始 RAM 磁盘映像和符号映射。
GRUB 将所选内核加载到内存并开始执行后,内核必须先从压缩文件中解压自己,才能执行任何有用的工作。内核解压后,加载
systemd
并将控制权交给它。
这标志着引导过程的结束。此时,Linux 内核和
systemd
正在运行,但由于没有其他程序运行,没有提供命令行的 shell,没有管理网络或其他通信链接的后台进程,计算机无法为最终用户执行任何生产性任务。
7. Linux 启动
启动过程在引导过程之后进行,将 Linux 计算机带入可操作状态。启动过程从内核接管系统控制权时开始。
7.1 文本模式启动
文本模式启动比默认的 GUI 启动模式显示更多信息,这使系统管理员更容易找到问题的根源。查看正常运行主机上的数据流有助于理解启动过程正常时的情况。文本和 GUI 启动最终都会到达
default.target
。
7.2 实验:探索文本模式启动
由于 Linux 启动速度快且会发出大量信息性消息,我们很难跟上大部分内容。不过,Linux 内核开发者提供了
dmesg
命令作为很好的替代方法。
以根用户身份执行以下命令:
[root@studentvm1 ~]# dmesg | less
[ 0.000000] Linux version 6.1.7-200.fc37.x86_64 (mockbuild@bkernel01.
iad2.fedoraproject.org) (gcc (GCC) 12.2.1 20221121 (Red Hat 12.2.1-4), GNU ld
version 2.38-25.fc37) #1 SMP PREEMPT_DYNAMIC Wed Jan 18 17:11:49 UTC 2023
[ 0.000000] Command line: BOOT_IMAGE=(hd0,gpt2)/vmlinuz-6.1.7-200.
fc37.x86_64 root=/dev/mapper/fedora_studentvm1-root ro rd.lvm.lv=fedora_
studentvm1/root rd.lvm.lv=fedora_studentvm1/usr
[ 0.000000] x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point
registers'
[ 0.000000] x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
[ 0.000000] x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
[ 0.000000] x86/fpu: xstate_offset[2]: 576, xstate_sizes[2]: 256
[ 0.000000] x86/fpu: Enabled xstate features 0x7, context size is 832
bytes, using 'standard' format.
[ 0.000000] signal: max sigframe size: 1776
[ 0.000000] BIOS-provided physical RAM map:
[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
[ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x00000000dffeffff] usable
[ 0.000000] BIOS-e820: [mem 0x00000000dfff0000-0x00000000dfffffff] ACPI data
[ 0.000000] BIOS-e820: [mem 0x00000000fec00000-0x00000000fec00fff] reserved
[ 0.000000] BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
[ 0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
[ 0.000000] BIOS-e820: [mem 0x0000000100000000-0x000000041fffffff] usable
[ 0.000000] NX (Execute Disable) protection: active
[ 0.000000] SMBIOS 2.5 present.
[ 0.000000] DMI: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[ 0.000000] Hypervisor detected: KVM
[ 0.000000] kvm-clock: Using msrs 4b564d01 and 4b564d00
<SNIP>
[ 3.749441] Run /init as init process
[ 3.749793] with arguments:
[ 3.749795] /init
[ 3.749797] with environment:
[ 3.749798] HOME=/
[ 3.749799] TERM=linux
[ 3.749800] BOOT_IMAGE=(hd0,gpt2)/vmlinuz-6.1.7-200.fc37.x86_64
[ 3.760797] systemd[1]: systemd 251.10-588.fc37 running in system mode
(+PAM +AUDIT +SELINUX -APPARMOR +IMA +SMACK +SECCOMP -GCRYPT +GNUTLS +OPENSSL
+ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN -IPTC +KMOD +LIBCRYPTSETUP
+LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB
+ZSTD +BPF_FRAMEWORK +XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified)
[ 3.763176] systemd[1]: Detected virtualization oracle.
[ 3.765139] systemd[1]: Detected architecture x86-64.
[ 3.765569] systemd[1]: Running in initial RAM disk.
[ 3.767893] systemd[1]: Hostname set to <studentvm1>.
[ 5.208337] systemd[1]: bpf-lsm: LSM BPF program attached
[ 5.309583] systemd[1]: Queued start job for default target initrd.target.
[ 5.310415] systemd[1]: Reached target initrd-usr-fs.target - Initrd /usr
File System.
[ 5.315207] systemd[1]: Reached target local-fs.target - Local File Systems.
[ 5.316402] systemd[1]: Reached target slices.target - Slice Units.
[ 5.317445] systemd[1]: Reached target swap.target - Swaps.
[ 5.318450] systemd[1]: Reached target timers.target - Timer Units.
[ 5.319616] systemd[1]: Listening on dbus.socket - D-Bus System Message
Bus Socket.
[ 5.321141] systemd[1]: Listening on systemd-journald-audit.socket -
Journal Audit Socket.
[ 5.322570] systemd[1]: Listening on systemd-journald-dev-log.socket -
Journal Socket (/dev/log).
[ 5.324061] systemd[1]: Listening on systemd-journald.socket -
Journal Socket.
类似
[ 5.321141]
这样的数字表示自内核开始运行以来的时间(以纳秒为单位)。
可以逐页查看数据,查找文件系统挂载和网络接口卡(NIC)配置等事件。
综上所述,本文详细介绍了 Linux 系统的 GRUB 引导过程、内核加载以及启动过程。通过实验演示了如何验证 GRUB 阶段 1.5、查看 Linux 内核、配置 GRUB 以及探索文本模式启动。了解这些过程有助于系统管理员更好地管理和维护 Linux 系统。
7.3 启动流程总结
为了更清晰地理解 Linux 的启动流程,下面用 mermaid 流程图展示:
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px
A([开机]):::startend --> B(BIOS自检):::process
B --> C(MBR引导):::process
C --> D(GRUB阶段1):::process
D --> E(GRUB阶段1.5):::process
E --> F(GRUB阶段2):::process
F --> G{选择内核}:::process
G -->|默认或选择| H(加载内核):::process
H --> I(内核解压):::process
I --> J(加载systemd):::process
J --> K(启动服务):::process
K --> L([进入系统]):::startend
这个流程图展示了从开机到进入系统的完整启动过程,每个阶段都紧密相连,任何一个环节出现问题都可能导致系统无法正常启动。
7.4 启动问题排查思路
当 Linux 系统启动出现问题时,可以按照以下步骤进行排查:
1.
检查硬件连接
:确保所有硬件设备连接正常,如硬盘、内存、电源等。
2.
查看 GRUB 菜单
:如果 GRUB 菜单无法正常显示,可能是 GRUB 配置文件损坏或 MBR 引导记录出现问题。可以尝试使用救援模式修复 GRUB。
3.
检查内核加载
:如果内核无法加载,可能是内核文件损坏或文件系统出现问题。可以通过查看
dmesg
命令输出,查找相关错误信息。
4.
检查服务启动
:如果系统启动到一半停止,可能是某个服务启动失败。可以使用
systemctl
命令查看服务状态,找出问题服务并进行修复。
8. 启动优化建议
为了提高 Linux 系统的启动速度,可以从以下几个方面进行优化:
8.1 减少不必要的服务
系统中可能存在一些不必要的服务在开机时自动启动,这些服务会占用系统资源,延长启动时间。可以使用
systemctl
命令查看和管理服务的启动状态:
# 查看所有服务的启动状态
systemctl list-unit-files --type=service
# 禁用不必要的服务
systemctl disable <service-name>
8.2 优化 GRUB 配置
可以通过调整 GRUB 配置文件中的参数来优化启动速度,例如减少
GRUB_TIMEOUT
的值,缩短等待用户选择内核的时间:
# 修改 /etc/default/grub 文件
GRUB_TIMEOUT=2
# 更新 GRUB 配置
grub2-mkconfig -o /boot/grub2/grub.cfg
8.3 使用快速文件系统
选择快速的文件系统可以提高磁盘读写速度,从而加快系统启动。例如,XFS 文件系统在性能上通常比 EXT4 更优,可以考虑将
/boot
分区或根分区格式化为 XFS 文件系统。
8.4 预加载常用库
使用
preload
工具可以在系统启动时预加载常用的库文件,减少程序启动时的加载时间:
# 安装 preload
yum install preload
# 启动 preload 服务
systemctl start preload
systemctl enable preload
9. 总结与展望
9.1 总结
本文详细介绍了 Linux 系统的 GRUB 引导和启动过程,包括数据重复区域与分区表位置、GRUB 各阶段的功能和作用、Linux 内核的加载和启动、以及启动过程中的文本模式和优化建议。通过实验演示和代码示例,帮助读者更好地理解和掌握这些知识。
9.2 展望
随着 Linux 技术的不断发展,启动过程也在不断优化和改进。未来,我们可以期待更快速、更稳定的启动方式,例如使用更高效的文件系统、优化内核加载算法等。同时,对于启动问题的排查和修复也将更加智能化,帮助系统管理员更快速地解决问题。
希望本文能够对读者理解和管理 Linux 系统的启动过程有所帮助,如果你在实际操作中遇到任何问题,欢迎在评论区留言讨论。
| 项目 | 详情 |
|---|---|
| 引导过程 | 涉及 GRUB 各阶段,确保内核正确加载 |
| 启动过程 | 从内核加载到系统进入可操作状态 |
| 优化建议 | 从服务管理、GRUB 配置等多方面提升启动速度 |
| 问题排查 | 提供了系统启动问题的排查思路和方法 |
通过对这些内容的深入学习和实践,你将能够更好地管理和维护 Linux 系统,确保其稳定、高效地运行。
超级会员免费看
15

被折叠的 条评论
为什么被折叠?



