第3章:Linux内核与根文件系统——内核配置裁剪与Buildroot构建
工控网关的软件栈,说白了就三层:引导程序、内核、根文件系统。内核是大脑,根文件系统是血肉。这一章,我带你亲手把这两样东西搞定。
你可能会问:直接用发行版的内核不行吗?行,但工控场景下,你不需要桌面、不需要显卡驱动、不需要一堆没用的模块。裁剪内核,一是为了减小体积,二是为了降低实时延迟——内核越小,调度路径越短。
本章核心目标:
- 理解内核配置裁剪的基本方法
- 打上PREEMPT_RT实时补丁,让Linux具备硬实时能力
- 用Buildroot从零构建一个最小根文件系统
3.1 内核源码与实时补丁的获取
先讲个我踩过的坑。几年前做一款运动控制网关,内核用的4.19,没打实时补丁。现场跑起来,偶尔出现几毫秒的抖动,电机就跟着抖一下。客户差点退货。后来老老实实上了PREEMPT_RT,问题解决。
所以,工控网关选内核,我建议直接上LTS版本 + 对应的RT补丁。版本号必须严格对应,差一个次版本号都打不上。
| 组件 | 推荐版本 | 下载地址 |
|---|---|---|
| Linux内核 | 5.10.x LTS | kernel.org |
| PREEMPT_RT补丁 | patch-5.10.x-rtxx | rt.wiki.kernel.org |
| Buildroot | 2023.02.x LTS | buildroot.org |
我的习惯:下载后先校验sha256sum,避免下载损坏。曾经有一次补丁文件不完整,编译到一半报错,排查了整整半天。
3.2 内核配置裁剪——做减法
内核配置,就是做减法。默认配置里有一大堆你永远用不到的东西:比如显卡驱动、无线网卡、蓝牙协议栈。工控网关只需要串口、网口、GPIO、I2C、SPI、CAN这些外设。
我一般这样操作:
- 先确定硬件平台——比如ARM Cortex-A7,用厂家提供的defconfig作为起点
- 运行make menuconfig——图形界面,逐项检查
- 关闭不需要的子系统——比如Sound card support、Multimedia support、GPU drivers
- 开启实时相关选项——这是关键
具体到实时配置,你需要打开以下选项:
General setup --->
Preemption Model (Fully Preemptible Kernel (Real-Time)) --->
[*] Preemptible RCU
[*] High Resolution Timer Support
[*] Enable RT mutexes
Kernel Features --->
[*] Tickless System (Dynamic Ticks)
[*] Full dynticks system (all CPUs)
Timer frequency ---> 1000 Hz
Processor type and features --->
[*] Support for real-time tasks
[*] Force threading of IRQs
注意:开启Fully Preemptible Kernel后,内核吞吐量会下降约5%-10%。但工控场景下,确定性比吞吐量重要得多。我曾经在一条产线上测试过,抖动从原来的2ms降到了50μs以内。
裁剪完成后,保存为.config文件。我习惯把它备份一份,命名为config_rt_gateway,方便后续复用。
3.3 编译内核与设备树
配置好了,就该编译了。命令不多,但参数要写对:
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
make zImage -j4
make dtbs
make modules
编译完成后,你会得到三个关键产物:
- zImage——压缩后的内核镜像,烧写到内核分区
- *.dtb——设备树二进制文件,描述硬件资源
- modules目录——内核模块,按需安装到根文件系统
这里有个细节:设备树一定要和硬件匹配。我见过有人拿错了dtb,结果网口不工作,排查了两天才发现是引脚复用配置错了。
3.4 Buildroot构建最小根文件系统
根文件系统,就是Linux启动后挂载的“/”目录。工控网关不需要桌面环境,不需要X11,甚至不需要bash——一个busybox就够了。
Buildroot是我最常用的工具。它不像Yocto那么重,也不像Debootstrap那么散。配置一次,编译一次,出来就是一个完整的根文件系统镜像。
我的配置思路:
| 组件类别 | 选择 | 说明 |
|---|---|---|
| Target options | ARM (little endian) | 匹配你的CPU架构 |
| Toolchain | Buildroot internal | 自动编译交叉工具链 |
| System configuration | Busybox + glibc | 轻量级用户空间 |
| Filesystem images | ext4 / squashfs | 生产环境推荐squashfs(只读) |
| Networking | dropbear + libcurl | SSH和HTTP客户端 |
| OPC UA | open62541 | 开源OPC UA实现 |
运行make menuconfig后,逐项勾选。我个人习惯先选一个最小配置,编译通过后再逐步添加功能。这样万一出问题,定位范围小。
避坑指南:我曾经一次性勾选了所有需要的包,结果编译到一半报依赖错误。后来学乖了,分三步走:先出最小系统,再加网络服务,最后加OPC UA库。每一步都编译验证一次。
3.5 根文件系统的目录结构
Buildroot编译完成后,在output/images目录下会生成rootfs.ext4或rootfs.squashfs。挂载后,你会看到这样的结构:
/
├── bin/ # busybox和基本命令
├── sbin/ # 系统管理命令
├── usr/ # 用户程序
├── etc/ # 配置文件
├── lib/ # 动态库
├── dev/ # 设备节点
├── proc/ # 进程文件系统
├── sys/ # 系统文件系统
├── tmp/ # 临时文件
├── var/ # 可变数据
└── mnt/ # 挂载点
这个结构比标准Linux发行版小得多——整个根文件系统只有8MB左右。你想想看,一个Ubuntu要几个GB,而工控网关只需要几MB。这就是裁剪的价值。
3.6 整合内核与根文件系统
内核和根文件系统都准备好了,接下来就是整合。我通常用SD卡或NAND Flash作为存储介质,分区方案如下:
| 分区 | 大小 | 内容 |
|---|---|---|
| boot | 16MB | zImage + dtb + u-boot |
| rootfs | 64MB | 根文件系统(squashfs只读) |
| data | 剩余空间 | 应用数据、日志、配置(可读写) |
启动参数中,内核需要知道根文件系统在哪里:
root=/dev/mmcblk0p2 rootfstype=squashfs rw console=ttyS0,115200
这里有个小技巧:根文件系统用squashfs只读挂载,可以防止意外写坏。应用数据放在data分区,即使系统崩溃,配置和日志还在。
3.7 本章知识结构图
下面这张图,把内核裁剪、实时补丁、Buildroot构建的流程串起来了。你可以把它当作操作路线图:
3.8 验证与测试
烧写完成后,上电启动。通过串口观察启动日志:
U-Boot 2023.04
...
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 5.10.100-rt60
[ 0.000000] Preemptible RCU enabled
[ 0.000000] High-resolution timers enabled
...
[ 2.345678] VFS: Mounted root (squashfs filesystem) readonly on device 179:2
[ 2.456789] Freeing unused kernel memory: 1024K
[ 2.567890] Run /sbin/init as init process
...
Welcome to Buildroot
gateway login: root
看到Preemptible RCU enabled和High-resolution timers enabled,说明实时补丁生效了。看到Mounted root (squashfs filesystem) readonly,说明根文件系统挂载成功。
登录后,运行uname -a确认内核版本,运行cat /proc/version查看实时配置。我一般还会跑一个简单的延迟测试:
cyclictest -t1 -p99 -n -i1000 -l100000
如果最大延迟在100μs以内,说明实时性达标。我在项目中测过,5.10内核打上RT补丁后,典型延迟在30-50μs之间,完全满足工控需求。
总结一下:内核裁剪的核心是“只保留你需要的”,实时补丁的核心是“让内核可抢占”,Buildroot的核心是“最小化”。这三步走完,你的工控网关就有了一个干净、实时、可靠的基础平台。