4、Linux内核改造:内核裁剪、实时性增强(PREEMPT_RT补丁)、设备树修改
好,咱们进入正题。这一章讲的是Linux内核改造,说白了就是给Linux“瘦身”和“提速”。你想想看,一个标准的Linux内核,功能多到吓人,但很多我们用不上。在嵌入式系统里,尤其是要和RTOS混搭的场景,内核必须精简,还得有实时性。
我个人习惯,拿到一个项目,先不急着写代码。先问自己三个问题:
- 这个系统需要哪些驱动?
- 实时性要求有多高?
- 硬件资源(内存、Flash)够不够?
这三个问题想清楚了,内核改造的方向就明确了。
4.1 内核裁剪:去掉你不需要的
内核裁剪,不是让你乱删代码。而是通过配置选项,把不需要的功能模块关掉。我见过不少新手,一上来就make menuconfig,然后一顿乱选,结果编译出来的内核要么跑不起来,要么缺驱动。
我的建议是:先确定你的硬件平台,再确定你的应用场景。比如,你用的是ARM Cortex-A系列,那x86相关的驱动统统可以关掉。你不需要文件系统?那把EXT4、Btrfs都去掉。
常用的裁剪手段:
- 关闭不用的架构支持:比如你只用ARM,那把x86、MIPS、RISC-V都关掉。
- 关闭不用的驱动:网卡、声卡、显卡,只留你硬件上有的。
- 关闭调试选项:比如DEBUG_FS、PRINTK_TIME,这些在正式产品里可以关掉。
- 关闭不用的文件系统:只保留你需要的,比如只保留EXT4和TMPFS。
重要提示:裁剪不是越狠越好。我曾经在一个项目里,为了省空间,把内核的模块加载功能也关了。结果后来发现,某个驱动必须用模块方式加载,搞得我不得不重新编译整个内核。嗯,这个坑我替你们踩过了。
裁剪后的内核,体积可以从几十MB降到几MB。我做过一个项目,裁剪后内核只有2.3MB,跑在8MB的Flash上,绰绰有余。
4.2 实时性增强:PREEMPT_RT补丁
Linux默认不是实时系统。它的调度延迟可能达到几十毫秒,这对工业控制、机器人来说,完全不能忍。怎么办?打PREEMPT_RT补丁。
PREEMPT_RT补丁,说白了就是把Linux内核变成一个“可抢占”的内核。什么意思?就是高优先级的任务可以随时打断低优先级的任务,哪怕后者正在内核态执行。
安装步骤:
- 下载对应内核版本的PREEMPT_RT补丁。注意,版本号必须完全匹配,差一个字母都不行。
- 解压内核源码,进入目录。
- 打补丁:
patch -p1 < patch-xxx-rt.patch - 配置内核:
make menuconfig,找到“Preemption Model”,选择“Fully Preemptible Kernel (RT)” - 编译安装。
小技巧:打补丁前,最好先备份原始内核源码。我习惯用git管理,打补丁前先commit一次,万一出问题,git checkout回来就行。
打完补丁后,内核的调度延迟可以降到几十微秒级别。我在一个电机控制项目里测试过,中断响应时间从原来的5ms降到了80μs,效果非常明显。
但要注意,PREEMPT_RT不是万能的。它主要解决的是内核态抢占问题。如果你的应用程序本身写得不好,比如频繁调用系统调用、大量使用自旋锁,那实时性还是会受影响。
警告:PREEMPT_RT补丁会增加内核的开销。因为抢占点多了,上下文切换也更频繁。如果你的CPU性能不强,反而可能降低整体吞吐量。所以,实时性和吞吐量之间,你得做个权衡。
4.3 设备树修改:让内核认识你的硬件
设备树(Device Tree),是Linux用来描述硬件的一种方式。以前用的是板级文件(board file),但那个太死板,换一个硬件就得改代码。设备树就好多了,它把硬件信息独立出来,内核启动时解析设备树,就知道有哪些外设、怎么配置。
设备树的文件后缀是.dts,编译后变成.dtb。修改设备树,其实就是修改.dts文件。
常见的修改场景:
- 修改内存大小:比如你的板子有512MB内存,但设备树里只配了256MB,那就得改。
- 添加或修改外设:比如你要用SPI接口的ADC,那就得在设备树里添加SPI节点,并指定ADC的型号和引脚。
- 修改引脚复用:同一个引脚,可能既可以用作UART,也可以用作GPIO。设备树里要明确指定。
举个例子,假设你要添加一个I2C设备:
&i2c1 {
status = "okay";
clock-frequency = <100000>;
temp_sensor: tmp102@48 {
compatible = "ti,tmp102";
reg = <0x48>;
};
};
这段代码的意思是:在I2C1总线上,挂一个TI的TMP102温度传感器,地址是0x48。内核启动后,会去匹配compatible字段,找到对应的驱动。
我在项目中遇到过一个问题:设备树里配的引脚和实际电路对不上。结果内核启动时,驱动加载失败,外设完全没反应。查了两天才发现,原来是设备树里把GPIO号写错了。嗯,从那以后,我每次改设备树,都会对着原理图一个一个引脚核对。
核心要点:设备树修改,一定要和硬件原理图、芯片手册对照着看。别想当然,也别偷懒。一个引脚配错,可能整个系统都起不来。
修改完设备树后,用dtc工具编译:
dtc -I dts -O dtb -o myboard.dtb myboard.dts
然后把生成的.dtb文件放到启动分区里,内核启动时就会加载它。
4.4 三者之间的关系
内核裁剪、PREEMPT_RT补丁、设备树修改,这三件事不是孤立的。它们共同决定了你的系统能不能跑起来、跑得快不快。
| 改造项 | 主要目的 | 常见坑点 |
|---|---|---|
| 内核裁剪 | 减小体积、降低资源占用 | 裁剪过度导致功能缺失 |
| PREEMPT_RT | 提升实时性、降低调度延迟 | 增加开销、可能降低吞吐量 |
| 设备树修改 | 适配硬件、正确描述外设 | 引脚配置错误、地址不匹配 |
我个人习惯,先做设备树修改,确保硬件能正常工作。然后做内核裁剪,把不需要的功能去掉。最后打PREEMPT_RT补丁,做实时性测试。这个顺序,能让你少走很多弯路。
好了,这一章的内容就这些。下一章,我们会讲如何把改造后的Linux内核和RTOS整合到一起,实现真正的混合部署。到时候,你会看到Linux和RTOS如何共享CPU、内存和外设,那才是真正的硬核内容。