嵌入式 Linux 同时包含启动固件、内核和用户空间。内核能运行并不代表系统服务已经可用;找不到根文件系统也不代表内核编译失败。按启动阶段划分问题,通常比反复更换镜像更有效。
从上电到应用
常见硬件链路是 Boot ROM 选择介质,早期启动阶段建立必要内存和时钟,Bootloader 加载内核、设备树以及可选 initramfs,内核初始化驱动并挂载根文件系统,随后启动 PID 1,由 init 系统启动应用。各 SoC 的安全启动和固件层次不同,不能把这条常见链路当成统一硬件规范。
| 产物 | 负责什么 | 常见错误 |
|---|---|---|
| Bootloader | 选择、校验和加载镜像,传递启动参数 | 地址重叠、介质布局、内存初始化问题 |
| 内核镜像 | 调度、内存、文件系统和设备驱动 | 架构错误、缺少根盘驱动、控制台配置错误 |
| DTB | 描述硬件连接、地址、中断和资源 | compatible 不匹配、引脚复用或时钟资源错误 |
| rootfs | 程序、运行库、配置、init | 缺少动态加载器、权限错误、PID 1 路径错误 |
| 应用服务 | 业务和服务依赖 | 配置缺失、设备未就绪、重启循环 |
设备树描述硬件,并不会凭空产生驱动。节点存在但内核没有合适驱动时,设备不会自动可用。启用驱动也不保证引脚、电源和时钟配置正确。
看懂 kernel command line
QEMU AArch64 virt 示例中,console=ttyAMA0 选择串口控制台,root=/dev/vda 指定根块设备,rootwait 等待该设备出现。实际设备名和控制台由目标平台决定,复制别的板卡参数可能完全没有输出。
rootwait root=/dev/vda console=ttyAMA0
initramfs 可在内存中提供早期用户空间,再切换到真正 rootfs;它与持久根文件系统的职责不同。静态链接程序较少依赖目标动态加载器,但通常更大;动态链接程序必须同时匹配 CPU ABI、加载器与运行库。
无板卡观察启动
按 Buildroot 实验 构建 QEMU virt 目标,使用该版本随附的启动脚本观察日志。直接让 QEMU 加载内核会跳过真实 Boot ROM 和部分 Bootloader 阶段,因此适合学习 Linux 启动与用户空间,不能验证一块真实板的 DDR 初始化或启动介质。
首次记录完整串口输出,标出内核开始、根文件系统挂载和 init 启动。练习时每次只修改一个启动参数,保留可恢复配置。本文未运行 QEMU 或实物镜像,命令依据固定 Buildroot 目标文档;本地已执行的流式应用见网关项目。
按最后可见阶段排障
完全无串口输出时先查控制台、连接、波特率、早期固件和镜像是否执行;显示内核日志却停在找根盘时,核对 root 参数、块设备、文件系统驱动是否内建以及镜像格式。出现找不到 init 时,除了文件是否存在,还要查执行权限、解释器路径和动态加载器。
启动性能分析先给各阶段打时间标记,再判断是加载、驱动等待还是服务依赖耗时。禁用一个慢服务前确认业务依赖;缩短启动时间不应靠丢失故障信息。
练习:给“内核已打印版本但找不到 /dev/vda”“/sbin/init 存在却不能执行”“应用先于设备就绪启动”各写一组检查命令和预期证据。不要只写“重装驱动”。
面试自查:Bootloader 与内核如何交接?DTB 和驱动是什么关系?initramfs 与 rootfs 怎样区别?为什么同为 ARM64 的二进制仍可能无法运行?
参考:Linux 对设备树的使用、Buildroot 2026.08 QEMU AArch64 目标、Linux 内核参数。