可以把 Linux 启动理解成:内核要跑起来,必须知道三件事:我是谁、我在哪、我要去哪里。
- 我是谁:板子上有哪些硬件?—— 由 DTB 告诉内核。
- 我在哪:根文件系统在哪个分区、用什么参数启动?—— 由 bootargs 告诉内核。
- 我要去哪里:最终进入哪个用户空间?—— 由 rootfs 提供。
如果内核还不认识硬盘、分区或文件系统,就需要 initrd/initramfs 先搭一座桥。
五个概念一句话理解
| 概念 | 像什么 | 它做什么 |
|---|---|---|
| Kernel | 操作系统的大脑 | 管理 CPU、内存、驱动、文件系统 |
| DTB | 硬件说明书 | 告诉内核板子上有哪些设备、地址在哪 |
| bootargs | 启动指令单 | 告诉内核根分区在哪、串口用哪个、是否等待设备 |
| initrd/initramfs | 临时小系统 | 内核启动早期先跑它,加载驱动后再切到真正的 rootfs |
| rootfs | 真正的系统盘 | 提供 /bin、/sbin、/etc、/lib、/dev 和用户程序 |
它们各自为什么需要?
1. Kernel:负责执行
内核镜像就是 Linux 本体,比如 Image、zImage、uImage。
它负责初始化 CPU、内存、中断、调度器、驱动和文件系统。
但内核本身不知道这块板子具体长什么样,也不知道根文件系统在哪个分区。
2. DTB:描述硬件
DTB 是设备树二进制文件,由 .dts 编译而来。
它告诉内核:
- CPU 有几个核;
- 内存多大;
- UART、I2C、SPI、GPIO 在哪里;
- eMMC/SD 控制器怎么接;
- 时钟、电源、中断如何连接。
有了 DTB,同一个内核镜像可以跑在不同板子上,只需要换 DTB。
3. bootargs:告诉内核怎么启动
bootargs 是 U-Boot 传给内核的一串命令行参数。
常见写法:
console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait rw
含义是:
console=ttyS0,115200:日志和终端走串口 0,波特率 115200;root=/dev/mmcblk0p2:根文件系统在 eMMC/SD 的第 2 个分区;rootwait:等设备准备好再挂载根分区;rw:以读写方式挂载。
bootargs 错了,内核可能找不到根分区,就会报:
VFS: Cannot open root device
4. initrd / initramfs:启动早期的临时根文件系统
initrd 和 initramfs 常被混着说,严格来说:
- initrd:老式机制,是一个块设备格式的内存盘镜像;
- initramfs:新式机制,是 cpio 归档,内核启动时解压到内存中。
现在大多数发行版默认用的是 initramfs,只是文件名仍常叫 initrd.img。
它的作用是:在内核还无法直接访问真正的根文件系统时,先提供一个临时环境。
临时环境里会做这些事:
- 加载存储控制器驱动;
- 加载文件系统模块;
- 等待 eMMC/SD/NVMe/SATA 等设备就绪;
- 解密磁盘;
- 激活 LVM/RAID;
- 找到真正的 root 分区;
- 切换过去,执行真正的
/sbin/init。
5. rootfs:系统真正的家
rootfs 是根文件系统,提供:
/bin、/sbin:命令;/lib:库文件;/etc:配置;/dev:设备节点;/proc、/sys:内核信息;/usr、/var、/home:应用和数据。
内核挂载 rootfs 后,会启动第一个用户进程,通常是 init 或 systemd,系统才算真正进入用户空间。
为什么 Debian / Ubuntu 需要 initrd?
Debian、Ubuntu 这类通用发行版要跑在很多不同硬件上,所以不能把所有驱动都编译进内核。否则内核会非常大,而且每次换硬件都要重新编译。
它们的典型做法是:
- 内核只内置最基础的驱动;
- 启动时先加载 initramfs;
- initramfs 里探测硬件、加载需要的内核模块;
- 找到真正的根分区;
- 挂载真正的 rootfs;
- 切换到 rootfs,启动
systemd。
比如根分区可能是:
/dev/sda2/dev/mmcblk0p2UUID=xxxx-xxxx- LVM 卷
- 加密分区
内核一开始可能并不知道该用哪个驱动访问这些设备,所以需要 initramfs 先帮忙“探路”。
嵌入式板子为什么有时不需要 initrd?
嵌入式系统通常是自己定制的 rootfs,比如用 Buildroot、Yocto 制作。
根文件系统往往直接放在 eMMC/SD 的某个分区,文件系统类型也固定,比如 ext4、squashfs。
如果内核已经把 eMMC/SD 驱动和文件系统驱动编译进去,就可以直接挂载 rootfs,不再需要 initrd。
所以可以这样理解:
- 嵌入式定制系统:内核知道硬件和分区,通常可以直接挂 rootfs;
- Debian/Ubuntu 通用发行版:硬件不确定、分区不确定,通常需要 initramfs 过渡。
用一句话串起来
DTB 告诉内核板子上有什么硬件,bootargs 告诉内核根分区在哪里,initramfs 在内核还不认识硬盘时先搭一座桥,rootfs 是系统最终运行的真正根目录,而 Kernel 负责把这些全部组织起来并启动用户空间。