4、Linux系统移植:Yocto构建TBOX专用系统、内核裁剪与驱动集成、文件系统定制

好,咱们进入正题。这一章讲的是Linux系统移植,说白了就是怎么给TBOX这个硬件“装上灵魂”。Yocto、内核裁剪、只读文件系统——这些词听着挺唬人,但拆开来看,每一步都有它的道理。我当年第一次用Yocto的时候,光编译就等了六个小时,结果还报错……嗯,后来才发现是源没配好。咱们今天争取不让你走这个弯路。

4.1 Yocto构建TBOX专用系统

Yocto是什么?它是一个构建嵌入式Linux系统的工具集。你想想看,TBOX这种车规级设备,不可能像PC一样装个Ubuntu就完事。我们需要一个“刚刚好”的系统——不多一个包,不少一个驱动。

我个人习惯用Yocto的 Poky 作为基础参考系统。为什么?因为它稳定,社区活跃,而且对ARM架构支持得特别好。TBOX的SoC大多是ARM Cortex-A系列,比如NXP的i.MX8、瑞萨的R-Car,Poky都能很好地适配。

构建流程大致是这样的:

  1. 初始化环境:下载Poky,运行 oe-init-build-env 脚本。
  2. 配置目标机器:在 local.conf 中设置 MACHINE 变量,比如 MACHINE = "imx8qm-var-som"
  3. 添加Meta层:TBOX需要额外的驱动和库,比如CAN通信、GNSS解析、V2X协议栈。这些都要通过 bblayers.conf 引入。
  4. 定制镜像:用 bitbake core-image-minimal 打底,再往里面加你需要的包。

关键点:TBOX的系统镜像一定要“瘦”。我见过有人把Python、GCC都编译进去,结果镜像200多MB,启动慢不说,还容易出安全漏洞。记住,TBOX不是开发板,是量产产品。

这里有个小技巧:用 IMAGE_INSTALL_append 来添加包,而不是直接改 local.conf。这样方便维护,也方便不同项目复用。

# 在你的自定义meta层中,比如 meta-tbox/recipes-core/images/tbox-image.bb
IMAGE_INSTALL_append = " \
    can-utils \
    libsocketcan \
    gpsd \
    openssl \
    v2x-stack \
"

我曾经在一个项目里,因为漏加了 can-utils,导致调试CAN总线时手忙脚乱。后来我学乖了,每次构建前都列一个“必装清单”,贴在工位上。

4.2 内核裁剪与驱动集成

内核裁剪,说白了就是“去掉你不需要的,留下你必需的”。TBOX的内核不需要支持显卡、声卡、USB键盘这些外设。但CAN、SPI、I2C、以太网这些一个都不能少。

我一般这样操作:

  1. 获取内核源码:从SoC厂商那里拿到BSP包,里面通常有打好了补丁的内核。
  2. 配置内核:运行 make menuconfig,逐项检查。
  3. 裁剪模块:把不需要的驱动都去掉,比如 CONFIG_SOUNDCONFIG_USB_HID 这些。
  4. 集成驱动:把TBOX特有的驱动加进去,比如V2X模组的PCIE驱动、GNSS的串口驱动。

提示:我个人习惯把内核配置保存为 defconfig,放在Yocto的recipes-kernel目录下。这样每次构建都能复现,不会出现“上次还能跑,这次怎么不行了”的尴尬。

驱动集成这块,最容易出问题的是 设备树。TBOX的硬件连接千奇百怪——CAN控制器挂在哪条SPI总线上?GNSS模块用哪个UART?这些都要在设备树里写清楚。

// 设备树片段:tbox.dts
&uart3 {
    status = "okay";
    pinctrl-0 = &pinctrl_uart3;
    gnss: gnss@0 {
        compatible = "u-blox,neo-m9n";
        current-speed = <115200>;
    };
};

&ecspi2 {
    status = "okay";
    can0: can@0 {
        compatible = "microchip,mcp2518fd";
        reg = <0>;
        spi-max-frequency = <20000000>;
    };
};

嗯,这里要注意:设备树的 compatible 字符串一定要和驱动里匹配的字符串完全一致。我吃过这个亏——少写了一个逗号,内核就是认不出设备。查了两天才发现,原来是手误。

4.3 文件系统定制:只读根文件系统

为什么TBOX要用只读根文件系统?你想想看,车在路上跑,系统突然写坏了一个配置文件,或者断电导致文件系统损坏——这可不是闹着玩的。只读根文件系统,就是为了保证系统在任何情况下都能正常启动。

实现方式其实不复杂:

  1. 构建根文件系统:用Yocto的 core-image-minimal 为基础,添加你需要的库和应用。
  2. 制作只读镜像:使用 squashfsext4 只读挂载。
  3. 分离可写分区:把日志、配置数据放到一个单独的可写分区,比如 /data/var

我推荐用 squashfs,因为它压缩率高,而且天生只读。一个原本100MB的根文件系统,压缩后可能只有40MB。对于TBOX这种存储空间有限的设备来说,非常实用。

警告:千万不要把 /etc 也做成只读!有些应用会在运行时修改配置文件,比如V2X协议栈的证书更新。正确的做法是:/etc 用overlayfs挂载,上层是可写分区,下层是只读的squashfs。

在Yocto中,可以通过 IMAGE_FEATURES 来启用只读根文件系统:

# local.conf 或你的镜像配方中
IMAGE_FEATURES_append = " read-only-rootfs"

这样Yocto会自动帮你处理好只读挂载和可写分区的映射。但说实话,自动处理有时候并不完美。我曾经遇到一个问题:系统启动后,/var/log 写不进去,因为Yocto默认把 /var 也放在了只读分区里。后来我手动在 fstab 里加了一行,把 /var/log 挂载到可写分区才解决。

# /etc/fstab 片段
/dev/mmcblk0p2   /data       ext4    defaults    0   0
/data/var/log    /var/log    none    bind        0   0

说白了,只读根文件系统就是“用空间换安全”。你牺牲了一点灵活性,但换来了极高的可靠性。对于TBOX这种安全至上的设备,这笔买卖绝对划算。

小结

这一章的内容,说白了就是三件事:用Yocto搭骨架,用内核裁剪做减脂,用只读文件系统上保险。每一步都有坑,但只要你按照流程来,多测试、多验证,就不会出大问题。

我记得第一次给TBOX做系统移植时,光内核就编译了十几遍。每次改一个配置,就要等半小时。后来我学会了用 ccache 加速编译,还把常用的配置项记在本子上。现在再做类似项目,基本一次过。

下一章我们会讲V2X协议栈的集成,那才是真正考验功力的时候。做好准备。