3. 内核裁剪基础:关闭无用驱动与子系统
内核裁剪这事儿,说白了就是给系统做减法。车载硬件资源就那么点,你塞一堆用不上的驱动进去,不光浪费Flash空间,还拖慢启动速度。我刚开始做车载项目时,就吃过这个亏——编译出来的内核镜像快20MB,烧进去发现根本跑不起来。
嗯,今天咱们就聊聊怎么把内核瘦下来。核心就三件事:关掉没用的驱动和子系统、搞懂模块和built-in怎么选、最后看看裁剪前后到底差多少。
3.1 关闭无用驱动与子系统
车载系统里,硬件是固定的。你想想看,一个车载娱乐主机,哪来的Wi-Fi网卡?哪来的蓝牙键盘?这些驱动统统可以关掉。
我个人习惯,先跑一遍 make menuconfig,然后按这几个维度去扫:
- 架构无关的驱动:比如显卡驱动(DRM)、声卡驱动(ALSA)、网络驱动。车载上只用得到特定的几款,其他的全关。
- 文件系统支持:车载一般用ext4、squashfs、ubifs。像什么btrfs、xfs、ntfs,用不上就关。
- 网络协议栈:车载不需要IPv6、IPSec、Netfilter全套。我一般只留IPv4和基本的TCP/UDP。
- 电源管理子系统:车载有自己的一套电源管理,内核自带的ACPI、APM这些可以关掉。
我的经验: 别一上来就猛关。先编译一个全功能版本跑起来,然后逐个模块关掉测试。我曾经一次性关了20多个选项,结果系统起不来,排查了整整一天。
下面这张图,是我整理的内核裁剪核心逻辑:
3.2 内核模块与built-in的选择策略
这里有个经典问题:某个驱动,到底编译成模块(.ko)还是直接编进内核(built-in)?
我的判断标准很简单:
- 启动必须用的:比如存储控制器、根文件系统驱动、串口调试。这些必须built-in。否则内核都挂不上根文件系统,模块从哪加载?
- 按需加载的:比如USB设备驱动、音频编解码器、显示控制器。这些做成模块,系统启动后再加载,能减小内核镜像体积。
- 调试用的:比如各种测试驱动、debugfs。做成模块,调试时加载,发布时直接删掉。
核心原则: built-in 增大镜像体积但减少启动依赖;模块减小镜像体积但需要额外的文件系统和加载时间。车载上,我倾向于把稳定、常用的驱动 built-in,不常用的做成模块。
举个例子,车载上的显示驱动:
# 显示控制器(必须built-in,否则无法显示开机画面)
CONFIG_DRM=y
CONFIG_DRM_ROCKCHIP=y
# 触摸屏驱动(可以做成模块,用户登录后才需要)
CONFIG_TOUCHSCREEN_GT9XX=m
# 音频驱动(做成模块,系统启动后加载)
CONFIG_SND_SOC_ROCKCHIP=m
我曾经在一个项目里,把所有驱动都做成模块,结果内核镜像只有3MB,但根文件系统里塞了20多个.ko文件。启动时一个个加载,反而比全built-in还慢。后来我学乖了——启动路径上的驱动,一律built-in。
3.3 裁剪前后体积对比
光说不练假把式。咱们看一组真实数据。这是我之前做的一个车载信息娱乐系统,基于ARM Cortex-A72平台:
| 配置项 | 裁剪前 | 裁剪后 | 缩减比例 |
|---|---|---|---|
| 内核镜像(zImage) | 18.2 MB | 4.1 MB | 77.5% |
| 设备树(DTB) | 128 KB | 96 KB | 25% |
| 内核模块(.ko文件) | 12.5 MB | 3.2 MB | 74.4% |
| 总内核体积 | 30.8 MB | 7.4 MB | 76% |
| 启动时间 | 8.2秒 | 3.1秒 | 62.2% |
看到没?从30MB瘦到7.4MB,启动时间从8秒降到3秒。这就是裁剪的威力。
注意: 裁剪不是越狠越好。我曾经为了追求极致体积,把内核压缩算法从gzip换成lzma,结果解压时间翻了一倍。启动时间反而变长了。一定要做实际测试,别只看镜像大小。
具体怎么操作?我一般用 make savedefconfig 生成精简配置,然后对比差异:
# 生成当前配置的精简版
make savedefconfig
# 对比原始配置
diff .config defconfig
这样能清楚看到哪些选项被关了。我习惯把裁剪记录写成脚本,下次换内核版本时直接复用。
3.4 避坑指南
最后分享几个我踩过的坑:
- 别关掉串口驱动:调试全靠它。我有一回关了串口,系统起不来连日志都看不到,只能重新烧录。
- 文件系统驱动要谨慎:根文件系统用的驱动必须built-in。我见过有人把ext4做成模块,结果内核启动后找不到根分区,直接panic。
- 网络驱动别乱关:车载虽然不需要Wi-Fi,但以太网和CAN总线驱动是必须的。OTA升级全靠它们。
- 测试要全面:裁剪后至少跑一轮压力测试。我曾经关掉了一个看起来没用的电源管理驱动,结果系统休眠后唤不醒。
我的习惯: 每次裁剪后,先用qemu模拟运行一遍,确认能正常启动。然后再烧到真机上测试。这样能省下不少反复烧录的时间。