2. 嵌入式Linux系统概览

嵌入式 Linux 并不是“把桌面 Linux 缩小”,而是围绕特定硬件板卡重新组织的一套软件栈。理解它的组成、启动流程以及 BSP 所处的位置,是后续板级适配与内核移植工作的认知基础。本节从系统组成切入,串联启动链路,再落到 BSP 定义与板级适配、内核移植的关系。

一、嵌入式 Linux 的组成

一个可运行的嵌入式 Linux 系统,通常由四个层次构成,自下而上依次是硬件、引导程序、内核与根文件系统,以及用户态应用。

  • 硬件层:SoC、DDR、eMMC/NAND、PMIC、以太网 PHY、Wi-Fi 模组、传感器等。板级差异主要来自这一层。
  • 引导程序(Bootloader):典型为 U-Boot,负责时钟与 DDR 初始化、加载内核与设备树、传递启动参数。
  • 内核与设备树:Linux 内核提供进程调度、内存管理、驱动框架;设备树(.dts/.dtsi)以数据方式描述板级硬件资源。
  • 根文件系统与用户态:BusyBox、systemd 或 Buildroot/Yocto 构建的 rootfs,承载库、配置与业务程序。

其中,Bootloader、内核配置、设备树与驱动适配共同构成了 BSP 的主要内容。用户态应用通常由产品团队开发,但它的运行依赖 BSP 提供的驱动与接口。

二、典型启动流程

嵌入式 Linux 的启动是一条自上而下、逐级接力的链路。以常见的 ARM64 平台为例:

  1. 上电复位:SoC 内部 BootROM 运行,按启动引脚或熔丝配置选择启动介质。
  2. SPL/TPL 阶段:从 eMMC、SD 或 SPI Flash 加载 U-Boot 的二级程序,完成 DDR 初始化。
  3. U-Boot 阶段:初始化串口、网络、存储,加载内核镜像与设备树,跳转执行。
  4. 内核阶段:解压内核、建立页表、初始化子系统,解析设备树并匹配驱动。
  5. 挂载 rootfs:内核执行 init 进程,进入用户态,启动服务与业务程序。

这条链路上任何一环出错,都会表现为“串口无输出”“卡在 Starting kernel”“找不到 rootfs”等典型现象。因此,排障时按阶段定位比盲目改代码更有效。

嵌入式 Linux 组成层次与启动接力 用户态应用 业务程序 / 服务 / 库 根文件系统 rootfs BusyBox / systemd / 配置 Linux 内核 + 设备树 驱动框架 / .dts 硬件描述 Bootloader(U-Boot) DDR 初始化 / 加载内核 硬件板卡(SoC / DDR / 外设) ① 上电复位 BootROM 选择启动介质 ② SPL / TPL DDR 初始化 ③ U-Boot 加载 Image + DTB ④ 内核启动 解析 DTB / 匹配驱动 ⑤ 挂载 rootfs → init BSP 覆盖范围 • U-Boot 板级配置 • DDR / 时钟参数 • 内核 defconfig • 设备树 .dts / .dtsi • 外设驱动适配 • 引脚复用 pinctrl • 电源与复位时序 • 启动参数 bootargs • 烧录与启动脚本 板级适配 = 让 BSP 匹配本板

三、BSP 的定义与边界

BSP(Board Support Package,板级支持包)是“让 Linux 在特定板卡上跑起来并可用”的最小软件集合。它通常包含:

  • U-Boot 的板级配置与 DDR/时钟参数;
  • 内核的 defconfig、设备树源文件与必要的驱动补丁;
  • 根文件系统的构建配置(Buildroot/Yocto 的 board 配置);
  • 烧录工具、启动脚本与调试文档。

需要强调的是,BSP 不等于“内核源码”。内核是通用基础设施,BSP 是面向具体板卡的“适配层”。同一颗 SoC 的不同板卡,内核主体可以相同,但 BSP 中的设备树、引脚配置、电源时序往往完全不同。

四、板级适配与内核移植的关系

这两个概念常被混用,实际是包含与被包含的关系。内核移植解决的是“内核能否在这颗 SoC 上运行”,板级适配解决的是“内核能否在这块板子上正确工作”。

对比项 内核移植 板级适配
目标 内核在 SoC 上可启动 板卡外设全部可用
主要对象 架构代码、SoC 驱动、时钟 设备树、pinctrl、电源、外设驱动
典型产物 可启动的 Image 可量产的 BSP 包
验证方式 串口打印到 init 外设逐项功能测试

实际项目中,两者往往交替进行:先完成内核移植让系统起来,再通过板级适配逐个点亮外设。若顺序颠倒,容易在“系统都起不来”的情况下调试外设,效率极低。

五、案例与常见误区

案例:某工业网关基于 i.MX6ULL,参考官方 EVK 的 BSP 启动正常,但换到自研板后卡在 U-Boot 的 DDR 初始化。原因是自研板 DDR 颗粒型号与 EVK 不同,时序参数未更新。修正 board/freescale/mx6ull_xxx/ 下的 DDR 配置后正常启动。这说明 BSP 中的板级参数必须与实物一致。

误区一:把设备树当成“配置文件随便改”。设备树中的 reg、interrupts、clocks 必须与硬件手册一致,写错会导致驱动 probe 失败且日志不明显。

误区二:认为内核移植完成就等于 BSP 完成。实际上外设适配、电源管理、量产烧录才是板级适配的主要工作量。

误区三:忽略 bootargs 与 rootfs 的匹配。常见的 Kernel panic - not syncing: VFS: Unable to mount root fs 多由 root= 参数或存储驱动缺失引起。

排查启动问题时,可先确认串口日志停在哪个阶段,再对照上图的启动接力逐段定位:BootROM 无输出查供电与启动介质;SPL 失败查 DDR 参数;U-Boot 卡住查环境变量与加载地址;内核 panic 查设备树与 rootfs 参数。

# 典型 U-Boot 启动参数示例
setenv bootargs 'console=ttySTM0,115200 root=/dev/mmcblk0p2 rw rootwait'
setenv bootcmd 'mmc dev 0; fatload mmc 0:1 0x80800000 Image; fatload mmc 0:1 0x83000000 stm32mp157a-xxx.dtb; booti 0x80800000 - 0x83000000'
saveenv