1. 启动流程概述:BIOS/UEFI 启动阶段、Bootloader 加载、内核初始化、根文件系统挂载

大家好,我是老李。做Linux系统工程师这么多年,每次有新人问我系统启动到底是怎么回事,我总会说:你先把启动流程搞明白,后面所有的问题都能迎刃而解。今天咱们就来聊聊这个最基础、也最关键的话题。

启动流程,说白了就是一台机器从按下电源键到出现登录提示符的全过程。我把它拆成四个阶段来讲:BIOS/UEFI、Bootloader、内核初始化、根文件系统挂载。嗯,咱们一个一个来。

1.1 BIOS/UEFI 启动阶段

机器通电后,CPU首先执行的是固件代码。这个固件,要么是传统的BIOS,要么是现代的UEFI。

BIOS(Basic Input/Output System),老古董了。它做的事情很简单:

  • 自检(POST):检查内存、CPU、硬盘等硬件是否正常
  • 读取MBR:从启动设备的主引导记录(第0扇区)读取512字节的引导代码
  • 跳转到Bootloader:把控制权交给MBR里的代码

UEFI(Unified Extensible Firmware Interface),这是后来替代BIOS的。它更灵活,也更安全。

  • 支持GPT分区表(BIOS只能用MBR)
  • 可以直接读取FAT32分区上的EFI应用程序
  • 支持安全启动(Secure Boot),防止恶意代码注入

我个人习惯:新机器一律用UEFI+GPT。为什么?因为MBR分区表最大只支持2TB磁盘,而且只能有4个主分区。你想想看,现在随便一块SSD都4TB起步了,用MBR不是给自己找麻烦吗?

避坑指南:我曾经遇到过一台服务器,BIOS里明明设置了从U盘启动,但死活进不去。查了半天,原来是U盘格式化成NTFS了,而BIOS只认FAT32。嗯,细节决定成败。

1.2 Bootloader 加载

BIOS/UEFI把控制权交给Bootloader后,真正的重头戏就开始了。Linux下最常见的Bootloader是GRUB2(GRand Unified Bootloader version 2)。

GRUB2做的事情:

  1. 加载自身:从磁盘读取GRUB的核心模块到内存
  2. 读取配置文件:解析 /boot/grub/grub.cfg,显示启动菜单
  3. 加载内核:根据用户选择,把vmlinuz内核文件和initramfs加载到内存
  4. 传递参数:把启动参数(如 root=/dev/sda1)传给内核
  5. 跳转到内核:把控制权交给内核的入口点

这里有个关键点:GRUB2需要能读取文件系统。它支持ext4、xfs、btrfs等常见文件系统,但如果你用了LVM或RAID,就得额外加载对应的模块。

注意:我曾经见过有人把 /boot 分区放在LVM上,结果GRUB2死活找不到内核。因为GRUB2的LVM支持是有限的,不是所有LVM配置都能识别。我的建议是:/boot 分区单独分出来,用ext4,不要用LVM。

1.3 内核初始化

内核被加载到内存后,开始执行初始化。这个过程大致分几步:

阶段 说明
解压缩内核 vmlinuz是压缩过的,内核先把自己解压到内存
初始化CPU 设置页表、中断描述符表、启动多核处理器
初始化内存管理 建立伙伴系统、slab分配器等
初始化设备驱动 扫描PCI总线、加载驱动、初始化存储控制器
挂载initramfs 把initramfs作为临时根文件系统挂载

你可能会问:为什么需要initramfs? 因为真正的根文件系统可能在RAID上、在LVM上、或者需要网络才能访问。内核本身没有这些驱动,所以需要一个临时的根文件系统来加载必要的模块。

initramfs本质上是一个压缩的cpio归档文件,里面包含了:

  • 必要的内核模块(如磁盘驱动、文件系统驱动)
  • udev设备管理器
  • 启动脚本(通常是 /init

我记得有一次,客户说服务器启动到一半卡住了。我远程一看,内核已经加载完了,但就是挂不上根文件系统。查了日志才发现,initramfs里缺少了NVMe驱动。因为客户新换了一块NVMe SSD,但initramfs还是旧的。重新生成一下initramfs就搞定了。

1.4 根文件系统挂载

这是启动流程的最后一步,也是最容易出问题的一步。

initramfs里的启动脚本会做这些事情:

  1. 加载必要的内核模块:比如磁盘驱动、文件系统驱动
  2. 发现根设备:根据内核参数 root= 找到根文件系统所在的设备
  3. 检查文件系统:如果 fsck 需要,会检查根文件系统的完整性
  4. 挂载根文件系统:把真正的根文件系统挂载到 /sysroot
  5. 切换到根文件系统:通过 pivot_rootswitch_root 切换到真正的根
  6. 启动init进程:执行 /sbin/init/lib/systemd/systemd

这里有个细节:根文件系统的挂载参数。你可以在内核参数里指定,比如:

root=/dev/sda1 rootfstype=ext4 rootflags=noatime,data=ordered

或者用UUID来指定,这样更稳定:

root=UUID=1234-5678-90ab-cdef

我的建议:永远用UUID来指定根设备。因为设备名(如 /dev/sda)可能会变,但UUID是唯一的。我曾经遇到过一台机器,插了个U盘后,原来的 /dev/sda 变成了 /dev/sdb,结果系统启动不了了。用UUID就没这个问题。

1.5 常见问题与排查思路

启动阶段出问题,通常表现在这几个地方:

  • BIOS/UEFI阶段:黑屏、报错、找不到启动设备。先检查启动顺序、磁盘连接、固件设置
  • Bootloader阶段:GRUB菜单不出现、报错"file not found"。检查 /boot 分区、GRUB配置
  • 内核初始化阶段:内核崩溃(Kernel Panic)、驱动加载失败。检查内核参数、initramfs
  • 根文件系统挂载阶段:挂载失败、进入紧急模式。检查 root= 参数、文件系统完整性

排查工具:

  • GRUB命令行:按 c 进入,可以手动加载内核和initramfs
  • 内核日志:启动时按 EscF12 查看详细输出
  • 紧急模式:如果根文件系统挂载失败,系统会进入紧急模式,可以手动修复

最后提醒一句:修改启动配置前,一定要备份。我见过太多人改了 /etc/default/grub 后忘了运行 update-grub,结果下次启动直接黑屏。嗯,备份是底线。

好了,启动流程的四个阶段就讲到这里。下一章咱们会深入Bootloader的配置和调优,到时候再聊。