Linux系统的启动过程
Linux系统的启动过程是一个精心设计的接力过程,涉及多个阶段,从硬件初始化到用户空间服务的完全启动。下面进行详细深入分析:
核心阶段概述
- 硬件初始化 (BIOS/UEFI)
- 引导加载程序 (Boot Loader)
- 内核初始化 (Kernel Initialization)
- initramfs (Initial RAM Filesystem)
- 用户空间初始化 (Systemd / SysV init / etc.)
- 登录管理器 / Shell
阶段 1:硬件初始化 (BIOS/UEFI)
- 电源开启 (Power On): 用户按下电源按钮。
- POST (Power-On Self-Test):
- 主板固件(BIOS或UEFI)执行硬件自检。
- 检查关键硬件组件:CPU、内存、显卡、存储控制器、键盘等是否正常工作。
- 如果检测到严重错误,会通过蜂鸣声或屏幕错误码提示。
- 固件初始化 (Firmware Initialization):
- 配置硬件:初始化CPU、内存控制器、芯片组、总线(PCIe, USB, SATA等)、时钟。
- 枚举连接的设备(存储设备、网卡、USB设备等)。
- 建立硬件设备列表和访问方式(如中断、I/O端口、内存映射)。
- 选择启动设备 (Boot Device Selection):
- 根据固件设置的启动顺序(Boot Order),查找可启动的设备(硬盘、SSD、USB驱动器、网络PXE等)。
- BIOS:查找每个设备第一个扇区(512字节)末尾的引导签名 0xAA55(Magic Number)。找到签名即认为该设备可引导,并加载该扇区(MBR)到内存 0x7C00 处执行。
- UEFI:查找EFI系统分区(通常是FAT32格式),然后在该分区下按照特定路径(如 \EFI\ubuntu\grubx64.efi)查找并直接加载EFI应用程序(Boot Loader的可执行文件)。UEFI本身理解分区表和文件系统,无需加载MBR。
- 移交控制权 (Handover):
- 硬件平台初始化完成。
- 将控制权移交给从选定启动设备加载的第一阶段引导加载程序(BIOS是MBR,UEFI是EFI Application)。
关键点:
- BIOS vs UEFI: UEFI更现代,支持更大的磁盘(GPT分区表)、更安全的启动(Secure Boot)、更快的启动速度、模块化设计。Secure Boot会验证引导加载程序的签名。
- MBR (Master Boot Record): 位于磁盘第一个扇区(512字节),包含:
- 446字节:Stage 1 Boot Loader(初始引导代码)。
- 64字节:分区表(4个主分区条目,每个16字节)。
- 2字节:引导签名 0x55AA(小端序存储为 0x55, 0xAA)。
- GPT (GUID Partition Table): UEFI使用的新分区方案,克服了MBR的限制(如分区数量、分区大小限制)。
阶段 2:引导加载程序 (Boot Loader)
主要任务: 找到并加载操作系统内核(vmlinuz-xxx)和可选的初始RAM磁盘映像(initrd.img-xxx 或 initramfs-xxx.img),并将控制权交给内核。
常见引导加载程序:GRUB2 (Grand Unified Bootloader version 2)
- GRUB2 的阶段 (BIOS 环境):
- Stage 1 (MBR): 被BIOS加载到 0x7C00 执行。其代码量极小,主要目的是加载Stage 1.5。它通常嵌入在MBR中或紧跟在MBR之后的扇区中。
- Stage 1.5: 位于MBR之后到第一个分区开始前的间隙(通常约31KB)。它包含了访问常见文件系统(如ext2, ext3, ext4, FAT)的基本驱动。它的核心任务是找到并加载位于 /boot/grub 目录下的 Stage 2 核心映像(core.img)。
- Stage 2 (core.img): 被加载到内存中。它提供了完整的GRUB功能:解析配置文件 /boot/grub/grub.cfg,显示引导菜单,允许用户选择操作系统或内核版本,加载模块(如支持LVM、RAID、加密、网络引导等)。其核心任务是加载Linux内核映像和 initramfs 映像到内存中。
- GRUB2 配置文件 (grub.cfg):
- 要加载的内核文件路径(如 /boot/vmlinuz-5.15.0-86-generic)。
- 要加载的 initramfs 文件路径(如 /boot/initrd.img-5.15.0-86-generic)。
- 传递给内核的命令行参数(root=, ro, quiet, splash, init=, 特定驱动参数等)。
- 根文件系统所在设备(在 initramfs 接管前可能需要)。
- 通常由工具(如 grub-mkconfig, update-grub)根据 /etc/default/grub 和 /etc/grub.d/ 下的脚本自动生成。
- 定义了引导菜单项、默认选项、超时时间。
- 每个菜单项指定了:
- 加载内核和 initramfs:
- GRUB2 利用其文件系统驱动(或Stage 1.5)从 /boot 分区读取 vmlinuz-xxx 和 initrd.img-xxx 文件到内存的特定位置。
- GRUB2 设置好内核启动所需的基本运行环境(如内存布局、视频模式)。
- 移交控制权给内核:
- GRUB2 执行一个特殊的跳转指令,将CPU控制权交给内存中已加载的Linux内核映像的入口点(通常是 startup_32 或 startup_64,取决于架构)。
- 同时,它将包含引导参数(cmdline)、内存磁盘地址(initramfs位置)、硬件信息(如BIOS内存映射)等数据的引导信息结构体(如struct boot_params on x86)传递给内核。
关键点 (UEFI):
- 在UEFI系统中,GRUB2 被编译为一个 EFI 应用程序(如 grubx64.efi)。
- UEFI 固件直接加载并执行这个 .efi 文件(位于EFI系统分区)。
- 后续流程(加载 grub.cfg, 内核, initramfs)与BIOS环境下的Stage 2类似。UEFI GRUB自身就包含了访问文件系统等所需的驱动。
阶段 3:内核初始化 (Kernel Initialization)
内核开始执行,接管硬件控制权,进行复杂的初始化工作,目标是挂载真正的根文件系统(/)并启动第一个用户空间进程(通常是 /sbin/init)。
- 解压与设置 (Architecture-Specific Setup):
- 设置CPU运行模式(x86: 从实模式/保护模式切换到长模式/64位模式)。
- 初始化基本内存管理:设置页表,启用分页(MMU)。
- 设置中断描述符表(IDT)和全局描述符表(GDT)。
- 检测CPU特性(FPU, MMX, SSE, etc.)。
- 初始化控制台(早期打印输出)。
- 内核通常是压缩的(如 vmlinuz 是 bzImage 格式)。内核入口代码首先解压自身到内存高端。
- 进行极其底层的、与CPU架构相关的初始化:
- 通用内核初始化 (start_kernel()): 这是内核C语言代码的入口点(init/main.c)。进行一系列关键子系统初始化:
- 初始化 RCU (Read-Copy Update): 高性能同步机制。
- 初始化定时器 (tick_init(), time_init()): 设置系统时钟和定时器中断。
- 初始化控制台 (console_init()): 如果之前是早期控制台,现在初始化完整控制台驱动。
- 初始化模块子系统 (module_init()): 支持可加载内核模块(LKM)。
- 初始化/proc, /sys等虚拟文件系统 (vfs_caches_init(), proc_root_init()).
- 初始化安全框架 (security_init()).
- 初始化设备模型 (do_basic_setup()->driver_init()): 建立设备、总线、驱动程序的模型,为后续探测硬件做准备。
- 在 start_kernel() 的末尾,调用 rest_init()。
- rest_init() 使用 kernel_thread() 创建内核线程 kernel_init (这就是未来的1号进程 /sbin/init 的内核线程部分)。
- rest_init() 创建另一个内核线程 kthreadd (2号进程,负责创建其他内核线程)。
- rest_init() 自身最终调用 cpu_startup_entry() 成为 0号进程 (idle 进程)。
- 初始化伙伴系统(物理页帧分配器)。
- 初始化虚拟内存管理(VM)。
- 解析并保留引导信息中传递的物理内存布局。
- printk() 初始化: 建立内核日志缓冲区。
- 陷阱和中断初始化: 设置异常处理程序,初始化中断控制器(如APIC/IOAPIC)。
- 调度器初始化 (sched_init()): 初始化进程调度器数据结构,创建0号进程 (idle 进程或 swapper 进程)。这是内核创建的第一个“进程”,它运行在内核空间,当CPU空闲时执行。
- 内存管理初始化 (mm_init()):
- 创建 init 进程上下文 (rest_init()):
- 其他重要初始化:
- 挂载根文件系统 (rootfs):
- 内核在初始化早期会在内存中挂载一个最小的、内存中的根文件系统 (rootfs)。这通常是一个 tmpfs 或 ramfs。
- 这个初始 rootfs 为内核后续操作(如加载模块、访问 initramfs)提供了一个基础的文件系统环境。
- 处理 initramfs (populate_rootfs()):
- 内核检查引导参数是否指定了 initramfs,以及GRUB是否加载了它。
- 如果存在 initramfs,内核将其解压并提取到刚刚挂载的初始 rootfs 中。这通常会覆盖 rootfs 中的部分内容。
- 这个解压出来的内容就是 initramfs 映像包含的文件和目录结构,它提供了在内核挂载真实根文件系统之前所需的关键工具、驱动和脚本。
- 移交控制权 (kernel_init):
- 内核执行 kernel_init 内核线程(即1号进程的内核部分)。
- 如果存在 initramfs,kernel_init 会尝试执行 initramfs 根目录下的 /init 程序(这是一个用户空间程序,尽管此时还没有完整的用户空间环境)。
- 如果没有 initramfs 或 /init 执行失败,内核会尝试直接执行指定的根文件系统上的 /sbin/init, /etc/init, /bin/init, /bin/sh 等(通过 root= 参数指定根设备)。
- 此时,内核将控制权交给用户空间的第一个程序 (/init 或 /sbin/init),标志着内核初始化阶段的结束和用户空间初始化的开始。
关键点:
- 0号、1号、2号进程: 内核创建的关键进程。
- initramfs 的作用: 为内核在挂载真实根文件系统之前提供必要的工具、驱动和脚本,解决了“先有鸡还是先有蛋”的问题(需要驱动访问根设备,但驱动可能在根设备上)。
阶段 4:initramfs (Initial RAM Filesystem)
initramfs 是一个临时的、基于内存的根文件系统。它的主要职责是为内核挂载真正的根文件系统 (/) 做准备,处理那些需要在内核启动后但在访问真实根设备之前完成的任务。
- /init 程序执行:
- 内核启动 initramfs 中的 /init 程序(通常是一个shell脚本或可执行文件,如BusyBox init)。
- 这个程序是 initramfs 运行时的核心控制流程。
- 关键任务:
- 这是 initramfs 的最后一步也是最关键的一步。
- 将当前进程的根目录从 initramfs 切换到新挂载的真实根文件系统 (/root)。
- 卸载或释放旧的 initramfs 占用的内存。
- 使用加载好的驱动和工具访问根设备(由内核参数 root= 指定)。
- 执行 mount 命令将真实的根文件系统挂载到 initramfs 内的某个目录(通常是 /root)。
- 组装软件RAID (mdadm)。
- 激活LVM卷组 (vgchange -ay)。
- 解锁加密卷(请求密码或读取密钥文件)(cryptsetup luksOpen)。
- 处理网络根文件系统(NFS)。
- 加载必要的内核模块: 加载访问根设备所需的驱动(如SCSI控制器驱动、RAID驱动、LVM驱动、加密驱动 dm-crypt 用于LUKS分区、文件系统驱动如 ext4, btrfs, xfs 等)。这些驱动可能不在内核镜像中,而是作为模块打包在 initramfs 里。
- 设备发现与等待: 探测硬件,可能需要等待慢速设备(如USB存储)就绪。
- 处理复杂存储:
- 挂载真正的根文件系统:
- 切换根 (pivot_root / switch_root):
- 执行真正的 init:
- 切换根成功后,initramfs 的 /init 程序(或它调用的脚本)会执行真实根文件系统上的 /sbin/init(或内核参数 init= 指定的程序)。
- 控制权正式移交给真实根文件系统上的初始化系统(如systemd, SysV init)。
- initramfs 的使命完成,其占用的内存通常会被回收。
关键点:
- 必要性: 对于使用复杂存储配置(LVM, RAID, 加密)、特殊文件系统、或根在网络的系统,initramfs 是必需的。
- 生成工具: 常用工具如 dracut (RHEL/Fedora/CentOS), mkinitramfs (Debian/Ubuntu), mkinitcpio (Arch Linux) 负责根据当前系统配置生成包含所需驱动和脚本的 initramfs 映像。
- 调试: 在启动时按特定键(如d或Esc)或在GRUB菜单项添加 break 或 rd.break 参数可以中断 initramfs 的执行进入shell进行调试。
阶段 5:用户空间初始化 (Systemd / SysV init / etc.)
真正的根文件系统挂载后,第一个用户空间进程 /sbin/init (通常是 systemd 或 SysV init 的符号链接) 开始运行。它负责启动所有用户空间的服务、守护进程、设置登录环境等。这里以systemd(现代主流发行版标准)为例:
- systemd 进程启动 (PID 1):
- 作为内核直接启动的 /sbin/init,成为系统的1号进程,是所有其他用户空间进程的祖先。
- 它读取其配置文件 /etc/systemd/system.conf 和 /usr/lib/systemd/system.conf。
- 确定启动目标 (default.target):
- graphical.target: 图形界面多用户模式。
- multi-user.target: 文本界面多用户模式。
- rescue.target: 单用户救援模式。
- systemd 启动的目标是达到一个预定义的“状态”(target)。默认启动目标通常是一个符号链接,指向例如:
- 默认目标由 /etc/systemd/system/default.target 符号链接指定。
- 并行启动与服务管理:
- Socket Activation: 按需启动服务。当有连接到达监听socket时,才启动对应的服务。避免服务闲置占用资源。
- D-Bus Activation: 类似Socket Activation,基于D-Bus消息激活服务。
- Mount & Automount Units: 管理文件系统挂载点。
- Path Activation: 监控文件路径变化来触发服务启动。
- systemd 的核心优势是并行启动服务,显著加速启动过程。
- 它通过定义服务之间的依赖关系(在 .service, .socket, .target 等单元文件中声明)来决定启动顺序。
- 关键机制:
- systemd 读取 /etc/systemd/system/ (系统管理员配置) 和 /usr/lib/systemd/system/ (发行版默认配置) 目录下的单元文件(.service, .target, .socket, .device, .mount, .timer 等)。
- 启动流程概要:
- 如果目标是 graphical.target,则继续启动其依赖的服务:显示管理器(如gdm.service, lightdm.service, sddm.service)。
- 显示管理器负责启动X Server或Wayland Compositor,并显示登录窗口。
- 所有定义为 multi-user.target 依赖的服务(如网络、远程登录sshd、打印cups、cron等)都启动完成。
- 系统进入命令行多用户模式,可以接受文本登录。
- 日志服务 (systemd-journald):收集和管理内核及服务日志。
- 网络服务 (systemd-networkd, NetworkManager):配置网络接口、IP地址、路由。
- 认证服务 (systemd-logind):管理用户登录会话。
- 定时器服务 (systemd-timedated)。
- D-Bus 系统总线 (dbus.service):进程间通信总线。
- 挂载 /proc, /sys, /dev, /dev/pts, /run 等虚拟文件系统。
- 设置hostname、locale、时钟(NTP)、内核参数 (sysctl)、加载内核模块(通过 .mount 和 .service 单元)。
- 激活swap空间。
- 初始化udev:管理 /dev 下的设备节点,处理热插拔事件。udev 规则在 /etc/udev/rules.d/ 和 /usr/lib/udev/rules.d/ 下。
- 设置随机数生成器种子。
- 基础系统初始化:
- 启动核心系统服务:
- 到达基本多用户状态 (multi-user.target):
- 到达图形界面状态 (graphical.target):
- 依赖解析与状态维护:
- systemd 持续监控所有单元的状态。
- 如果服务崩溃,systemd 可以配置为自动重启。
- 提供强大的命令(systemctl, journalctl)管理服务、查看日志、分析启动性能。
SysV init (传统方式) 对比:
- 使用 /etc/inittab 文件定义默认运行级别。
- 运行级别 (0-6) 对应不同状态(0关机,1单用户,3多用户文本,5图形)。
- 每个运行级别对应 /etc/rcX.d/ (X为运行级别) 目录,包含以 S(Start) 或 K(Kill) 开头的脚本链接,指向 /etc/init.d/ 下的实际脚本。
- 按脚本文件名顺序(字母顺序)串行执行 S 脚本启动服务,执行 K 脚本停止服务。
- 启动速度较慢,依赖关系管理复杂(通常靠脚本命名顺序和脚本内部处理)。
阶段 6:登录管理器 / Shell
- 文本登录 (如果目标是 multi-user.target):
- 系统启动 getty 服务(如 agetty)。
- getty 在虚拟终端 (tty1-tty6) 上显示 login: 提示符。
- 用户输入用户名和密码。
- 认证过程(通常通过 PAM - Pluggable Authentication Modules)。
- 认证成功后,启动用户指定的登录 shell (如 /bin/bash, /bin/zsh),通常在 /etc/passwd 中定义。
- shell 读取并执行其配置文件(如 .bashrc, .zshrc)。
- 图形登录 (如果目标是 graphical.target):
- 启动一个用户会话管理器(如 gnome-session, startplasma-x11, sway)。
- 会话管理器加载用户的桌面环境(DE)或窗口管理器(WM),启动相关的用户级程序(面板、文件管理器、设置守护进程等)。
- 执行用户的自动启动程序(~/.config/autostart/, ~/.xinitrc 等)。
- 显示管理器 (DM) 启动并显示图形登录界面。
- 用户选择用户并输入密码。
- 认证(同样通过PAM)。
- 认证成功后,DM:
- 用户进入图形桌面环境。
总结与可视化流程
+————————–+
| Power On |
+————+————-+
|
v
+————————–+
| BIOS/UEFI Firmware |
| - POST |
| - HW Init |
| - Find Boot Device |
+————+————-+
| (Loads MBR / EFI App)
v
+————————–+
| Boot Loader (GRUB2) |
| - Loads menu |
| - Loads kernel & initramfs |
+————+————-+
| (Hands off to kernel entry point)
v
+————————–+
| Linux Kernel |
| - Decompress self |
| - Arch-specific setup |
| - start_kernel() |
| * Core subsystems |
| * Create PID 0, 1, 2|
| - Mount rootfs (tmpfs) |
| - Extract initramfs |
| - Run /init (PID 1) |
+————+————-+
| (User space begins)
v
+————————–+
| initramfs /init |
| - Load modules (drivers)|
| - Assemble RAID/LVM |
| - Unlock crypto |
| - Mount real root (/) |
| - pivot_root/switch_root|
| - Exec /sbin/init |
+————+————-+
| (Real root FS)
v
+————————–+
| Systemd (PID 1) |
| - Parse unit files |
| - Start base system |
| - Reach default.target |
| - Start services |
+————+————-+
|
+——————-> [multi-user.target] —> Getty —> Login Shell
| (Text Login)
|
v
+——————-> [graphical.target] —> Display Manager —> Desktop Session
(Graphical Login)
深入理解 Linux 启动过程对于系统管理员至关重要,它能帮助:
- 故障诊断: 准确定位启动失败发生在哪个阶段(BIOS/UEFI? GRUB? Kernel Panic? initramfs? systemd service?)。
- 性能优化: 分析启动时间瓶颈(使用 systemd-analyze blame, systemd-analyze critical-chain, dmesg)。
- 系统定制: 修改内核参数、GRUB配置、initramfs内容、systemd服务单元。
- 安全加固: 配置Secure Boot、理解initramfs加密解锁过程、管理服务启动。
- 应急恢复: 使用GRUB编辑启动参数进入单用户模式/rescue模式,使用initramfs shell修复系统。