Linux 启动过程详解:从开机到用户登录的完整流程
Linux 系统的启动是一个从硬件初始化到用户空间就绪的复杂过程,涉及固件、内核、初始化系统等多个层面。理解启动流程不仅有助于系统故障排查,还能深入掌握 Linux 的底层运行机制。本文将以传统 SysVinit 系统为例,详细解析启动的五个核心阶段,并补充现代 systemd 系统的差异。
内核引导(Boot Loader 阶段)
这是启动的第一个阶段,负责从硬件到内核的交接,分为 BIOS/UEFI 自检 和 引导程序加载 两步。
BIOS/UEFI 自检(硬件初始化)
- BIOS(基本输入输出系统):传统固件接口,开机后首先运行,负责检测 CPU、内存、硬盘等硬件是否正常(即 “POST 自检”)。
- UEFI(统一可扩展固件接口):现代固件接口,功能与 BIOS 类似,但支持更大的硬盘、更快的启动速度和图形化界面。
- 核心任务:确定启动设备(如硬盘、U 盘、光驱),并读取设备的第一个扇区(MBR 主引导记录,传统 BIOS)或 EFI 系统分区(UEFI)。
引导程序(Boot Loader)加载内核
引导程序是位于启动设备第一个扇区的小程序,负责加载 Linux 内核。常见的引导程序有 GRUB(Grand Unified Bootloader)和 LILO(Linux Loader),其中 GRUB 因支持多系统引导而被广泛使用。
GRUB 的工作流程:
- 阶段 1:从 MBR 加载 GRUB 核心代码(占 512 字节,仅够启动下一步)。
- 阶段 1.5:加载位于 MBR 之后的驱动,使 GRUB 能识别内核所在的文件系统(如 ext4、xfs)。
- 阶段 2:读取
/boot/grub/grub.cfg配置文件,显示启动菜单(如选择不同内核版本或操作系统)。 - 加载内核:用户选择后,GRUB 将 Linux 内核(
/boot/vmlinuz-<version>)和初始 RAM 磁盘(/boot/initramfs-<version>.img)加载到内存。- 内核(vmlinuz):Linux 核心程序,负责硬件管理和进程调度。
- 初始 RAM 磁盘(initramfs):临时根文件系统,包含启动阶段必需的驱动(如硬盘驱动),帮助内核挂载实际根分区。
内核初始化(Kernel 阶段)
内核被加载到内存后,接管系统控制权,完成从硬件到用户空间的过渡。
内核自检与硬件初始化
- 内核解压后,首先初始化 CPU、内存管理单元(MMU)、中断控制器等核心硬件。
- 加载 initramfs 中的驱动模块,识别并初始化硬盘、网卡等外设。
挂载根文件系统
- 内核通过 initramfs 中的脚本找到并挂载实际根分区(如
/dev/sda1),挂载方式由/etc/fstab或内核参数(如root=/dev/sda1)指定。 - 卸载 initramfs,切换到根文件系统。
启动第一个用户态进程
内核完成初始化后,启动 init 进程(传统系统)或 systemd 进程(现代系统),并将进程号(PID)设为 1,作为所有用户态进程的父进程。
- 传统 SysVinit 系统:执行
/sbin/init。 - systemd 系统:执行
/usr/lib/systemd/systemd。
初始化系统(Init 阶段)
初始化系统是用户态的第一个进程(PID=1),负责启动后续所有服务和进程。
传统 SysVinit 系统(基于 /etc/inittab)
- 读取运行级别:init进程首先解析/etc/inittab文件,确定系统运行级别(Runlevel):
- 0:关机
- 1:单用户模式(用于修复系统)
- 2:多用户模式(无网络)
- 3:完全多用户模式(命令行,服务器默认)
- 4:预留
- 5:图形化模式(带桌面环境)
- 6:重启
- 执行系统初始化脚本:根据运行级别,首先执行/etc/rc.d/rc.sysinit(系统初始化核心脚本),完成以下任务:
- 激活交换分区(swap)。
- 检查磁盘完整性(
fsck)。 - 设置系统时钟、主机名。
- 加载内核模块(
/etc/modules.conf)。 - 挂载
/etc/fstab中定义的文件系统(如/home、/tmp)。
现代 systemd 系统(基于目标单元)
systemd 用 “目标(target)” 替代传统运行级别,通过配置文件和依赖关系管理服务启动:
- 核心目标:
multi-user.target:对应运行级别 3(命令行多用户)。graphical.target:对应运行级别 5(图形化)。rescue.target:单用户模式。
- 启动流程:
- 内核启动
systemd后,systemd读取/etc/systemd/system/default.target确定默认目标。 - 按依赖关系启动目标所需的服务(
.service)、挂载点(.mount)等单元(unit)。 - 替代
rc.sysinit的功能由多个基础服务(如systemd-fsck、systemd-sysctl)共同完成。
- 内核启动
启动系统服务与建立终端
初始化系统完成基础配置后,开始启动用户态服务并建立终端,为用户登录做准备。
启动后台服务
- SysVinit 系统:根据运行级别,执行
/etc/rc.d/rc<N>.d目录下的脚本(N为运行级别):- 脚本命名格式:
Sxx<service>(启动服务,xx为优先级)或Kxx<service>(停止服务)。 - 常见服务:
sshd(SSH 服务)、crond(定时任务)、network(网络服务)。
- 脚本命名格式:
- systemd 系统:通过目标单元的依赖关系自动启动服务(如
sshd.service),可通过systemctl list-dependencies查看依赖链。
建立终端(TTY)
- 系统启动多个虚拟终端(TTY),供用户登录:
- 传统系统:
init进程启动/sbin/mingetty或/sbin/getty程序,创建 TTY 设备(通常 6 个,Ctrl+Alt+F1至F6切换)。 - systemd 系统:由
getty@.service管理,默认启动tty1至tty6。
- 传统系统:
- 图形化模式下,还会启动显示管理器(如 GDM、LightDM),提供图形登录界面。
用户登录系统
终端就绪后,用户可通过命令行或图形界面登录,完成启动的最后一步。
命令行登录(TTY 或 SSH)
- 用户输入用户名和密码后,
login程序验证身份(通过/etc/passwd和/etc/shadow)。 - 验证成功后,加载用户环境(
~/.bash_profile、~/.bashrc),启动 shell(默认bash)。
图形化登录
- 显示管理器(如 GDM)验证用户身份后,启动桌面环境(如 GNOME、KDE),加载用户配置。
登录后的进程树
登录成功后,用户进程以 init/systemd(PID=1)为根,形成完整的进程树:
1 | systemd(1) → login(1000) → bash(1001) → user commands... |