Linux 系统启动流程详解:从上电到 Shell 的一次完整旅程 🚀
一篇面向工程师 / 学生 / 爱好者的 Linux 启动流程文章,力求做到:
- 不跳步
- 不神秘化
- 不只讲“是什么”,更讲“为什么这样设计”
一、为什么要理解 Linux 启动流程?🤔
很多人第一次接触 Linux 启动,是从这些现象开始的:
- 机器卡在 Starting kernel…
- systemd 服务卡住,黑屏几十秒
- 启动很慢,但不知道慢在哪
- 内核 panic,却不知道发生在启动的哪一阶段
理解启动流程,本质上是理解三个问题:
- 控制权在什么时候交给了谁?
- 系统能力是如何一步步“被解锁”的?
- 出问题时,日志和线索应该去哪里找?
二、从 Reset 到第一条指令:启动的真正起点
很多启动流程文章都会从“Bootloader 开始”讲起,但在工程视角下,这是不完整的。
系统启动并不是“突然进入 Bootloader”,而是从一次 Reset / 上电 开始,CPU 按架构规范执行一条被硬件强制规定的第一条指令。
理解这一点,是把 Reset、BootROM、Bootloader、UEFI 串成一条连续因果链的关键。
Bootloader / UEFI:把“裸硬件”变成“可启动系统”
有了前面的铺垫,我们现在可以清楚地定义 Bootloader 的位置:
Bootloader 是 Reset 之后的“第二跳”,而不是第一跳。
Reset 之后发生了什么:CPU、复位向量与 BootROM
1️⃣ Reset 并不是“重启 Linux”,而是“重新上电式接管 CPU”
无论是:
- Power-on Reset
- Watchdog Reset
- Software Reset
- Brown-out Reset
在硬件层面,效果都是一致的:
CPU 寄存器被强制置为已知状态,程序计数器(PC)跳转到“复位向量(Reset Vector)”地址。
这个地址:
- 不是 Linux 决定的
- 不是 Bootloader 决定的
- 而是 CPU 架构 + SoC 设计决定的
例如:
- ARM Cortex-A:通常从
0x00000000或0xFFFF0000 - x86:固定从
0xFFFFFFF0
2️⃣ Reset Vector 里通常是什么?——不是 Bootloader
一个常见误区是:
Reset → Bootloader
实际上中间还隔着一层:BootROM。
BootROM 的特点:
- SoC 厂商固化在芯片里的只读代码
- 不可修改
- 体积极小
- 只做“最小可信启动”
它的职责通常包括:
- 初始化最基础的时钟 / SRAM
- 判断启动介质(eMMC / SPI NOR / NAND / USB)
- 加载下一阶段代码到内存
- 跳转执行
📌 因此第一段“软件”并不是你刷的 bootloader,而是 SoC 内建的 BootROM。
3️⃣ BootROM → Bootloader / UEFI:第一次控制权交接
BootROM 完成最小初始化后,会:
- 从启动介质加载下一阶段镜像
- 将其放入 SRAM / DRAM
- 显式跳转到该镜像的入口地址
这一步,才是真正意义上的:
进入 Bootloader / UEFI
不同平台的差异在于:
- 加载的是 U-Boot SPL / BL2 / BL31
- 还是 UEFI 的 SEC / PEI 阶段
但本质完全一致:
上一阶段通过一次明确的跳转,把 CPU 控制权交给下一阶段。
三、Linux 启动的宏观分层视角 🧠
在宏观上,Linux 启动可以分为 6 个阶段:
每一层都有非常清晰的职责边界:
| 阶段 | 核心职责 |
|---|---|
| 上电 | 硬件进入已知状态 |
| Bootloader | 装载内核 |
| Kernel | 建立操作系统核心能力 |
| initramfs | 挂载真实根文件系统 |
| init | 拉起用户空间 |
| 服务 | 提供功能 |
下面我们逐层拆解。
四、上电 & 固件阶段(Firmware)⚡
1️⃣ 上电发生了什么?
当你按下电源键,CPU 会发生:
- 复位(reset)
- 程序计数器(PC)跳转到一个 固定地址
这个地址由 CPU 架构规定:
- x86:通常在 BIOS / UEFI ROM
- ARM:SoC 内部 Boot ROM
⚠️ 注意:此时还没有 Linux,甚至没有内存管理。
2️⃣ BIOS vs UEFI(简要科普)
- BIOS:传统方式,逐渐淘汰
- UEFI:现代平台主流
UEFI 的典型职责包括:
- 内存初始化
- PCIe 设备枚举
- 加载 EFI 程序(如 GRUB)
五、Bootloader:系统的“引导员” 👢
1️⃣ Bootloader 是什么?
Bootloader 是一段 非常早期运行的软件,核心任务只有一个:
把 Linux 内核加载到内存,并跳转执行
常见 Bootloader:
- GRUB(PC / 服务器)
- U-Boot(嵌入式 / 车载)
2️⃣ Bootloader 的典型流程
Bootloader 会向内核传递:
- kernel cmdline
- 设备树(DTB)或 ACPI 表
- initramfs 地址
3️⃣ kernel cmdline 很重要 🧩
例如:
root=/dev/sda2init=/sbin/initloglevel=7
很多启动问题,答案就在 cmdline 里。
六、Linux Kernel 启动:内核接管世界 🐧
当 Bootloader 跳转后,Linux 内核正式开始执行。
1️⃣ 解压与早期初始化
内核启动的第一步通常是:
- 自解压(zImage / bzImage)
- 建立最基本的页表
此阶段特点:
- 不能用 printf
- 没有完整内存管理
2️⃣ start_kernel():内核主入口
所有架构最终都会进入:
start_kernel();
它会完成:
- 中断系统初始化
- 调度器初始化
- slab / buddy 内存系统
- 初始化各类子系统
3️⃣ 设备初始化与驱动加载
驱动初始化顺序大致是:
- 核心子系统(CPU / IRQ / MM)
- 总线(PCI / platform)
- 设备驱动
设备树(DTB)在这里发挥关键作用。
七、initramfs:启动中的“过渡根文件系统” 📦
1️⃣ 为什么需要 initramfs?
问题:
内核启动时,真实根文件系统还不能访问怎么办?
解决方案:
用一个临时的、内存里的 rootfs
这就是 initramfs。
2️⃣ initramfs 里通常有什么?
/init脚本- 必要的存储驱动
- LVM / dm-crypt 工具
它的使命只有一个:
找到并挂载真正的 rootfs
3️⃣ rootfs 切换流程
如果这里失败,通常会掉进:
- initramfs shell
- kernel panic: unable to mount root fs
八、init / systemd:用户空间的起点 🧑💻
1️⃣ PID 1 的特殊地位
内核完成初始化后,会执行:
execve(/sbin/init)
这个进程:
- PID = 1
- 不能随便退出
- 承担“系统托孤人”角色
2️⃣ systemd 在做什么?
systemd 的职责包括:
- 挂载文件系统
- 拉起基础服务
- 管理依赖关系
它将系统组织成 Unit:
- service
- socket
- target
3️⃣ 启动依赖关系示意
systemd 的优势在于:
- 并行启动
- 依赖可视化
- 状态可观测
九、用户空间服务:系统真正“活了” 🎉
当 systemd 进入目标 target 后:
- 网络服务启动
- 图形界面出现
- 应用程序运行
此时:
系统已完成启动
但对工程师来说:
启动“完成” ≠ 启动“健康”
十、启动阶段常见问题定位 🧯
1️⃣ 启动卡住怎么办?
先判断卡在哪一层:
| 现象 | 可能阶段 |
|---|---|
| 黑屏无输出 | Bootloader / Kernel early |
| 有 kernel log | initramfs / rootfs |
| systemd 超时 | 服务依赖 |
2️⃣ 常用调试手段
earlyprintkloglevel=7systemd.log_level=debug
十一、总结:启动流程的本质 🧩
Linux 启动并不是魔法,而是一条:
控制权逐步下放、系统能力逐层解锁的过程
从固件到内核,从内核到用户空间,每一步都非常克制、清晰。
理解它,你将:
- 更快定位启动问题
- 更自信修改启动配置
- 不再害怕“系统起不来”
📌 如果你愿意,下一篇可以深入:
- systemd 启动优化
- 启动耗时分析(systemd-analyze)
- 车载 / 嵌入式启动裁剪策略
欢迎交流 👋

981

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



