4、配置内核:通过 make linux-menuconfig 定制 Linux 内核,添加或删除驱动模块
好,到了这一步,咱们的 Buildroot 已经能把一个基础的内核编译出来了。但说实话,那个默认配置通常很「干净」——干净到可能连你板子上的网卡、声卡、触摸屏驱动都没有。
所以这一节,我们就来亲手折腾一下内核。说白了,就是通过 make linux-menuconfig 这个命令,打开一个图形化的配置界面,把咱们需要的驱动勾上,不需要的统统关掉。
4.1 为什么非要手动配内核?
你可能想问:Buildroot 不是有默认配置吗?为什么还要自己进去改?
嗯,我刚开始用 Buildroot 时也这么想。结果第一次把镜像烧到板子上,发现网卡不工作,串口只能输出不能输入…… 折腾了半天,才发现是内核里对应的驱动模块没编译进去。
说白了,Buildroot 的默认内核配置只是一个「最小可用集」。它保证你能启动,但外设驱动基本靠猜。你的板子用的是哪颗芯片、哪个型号的网卡、哪个接口的显示屏——这些都得你自己去告诉内核。
核心原则:内核配置的原则是「够用就好」。不要一股脑把所有驱动都选上,那样编译出来的内核又大又慢,还容易出冲突。
4.2 进入内核配置界面
在 Buildroot 的顶层目录下,执行:
make linux-menuconfig
等一下,这里有个小坑。我第一次执行这个命令时,等了半天没反应。后来发现是因为 Buildroot 还没下载和解压内核源码。它会先自动完成下载、解压、打补丁这些步骤,然后才弹出配置界面。所以如果看到终端在刷屏,别急,那是正常流程。
等一会儿,你会看到一个蓝底白字的界面,类似下面这样:
Linux/arm 5.10.24 Kernel Configuration
─────────────────────────────────────────────
General setup --->
Enable loadable module support --->
Enable the block layer --->
System Type --->
Bus support --->
Kernel Features --->
Boot options --->
CPU Power Management --->
Floating point emulation --->
Userspace binary formats --->
Device Drivers --->
File systems --->
Security options --->
Cryptographic API --->
Library routines --->
Kernel hacking --->
─────────────────────────────────────────────
<Select> <Exit> <Help>
这个界面和 make menuconfig 一模一样,操作方式也一样:方向键移动,回车进入,空格或 Y 键选中,N 键取消。
4.3 添加驱动模块的实战流程
我以最常见的场景为例——给一块 ARM 板子添加 USB 网卡驱动和 I2C 驱动。你跟着走一遍,就能举一反三了。
4.3.1 添加 USB 网卡驱动
假设你的板子用的是 RTL8152 或 RTL8153 这种 USB 转以太网芯片。进入:
Device Drivers --->
Network device support --->
USB Network Adapters --->
<*> Realtek RTL8152/RTL8153 Based USB Ethernet Adapters
注意,这里要用 <*> 而不是 <M>。为什么?<*> 表示编译进内核,<M> 表示编译成模块。对于根文件系统里必须有的驱动(比如网卡、存储),我建议直接编译进内核。否则启动时还得先加载模块,但模块又放在文件系统里——这就成了「先有鸡还是先有蛋」的问题。
我的习惯:所有跟启动、网络、存储相关的驱动,一律编译进内核。其他外设(比如摄像头、声卡)可以编译成模块,按需加载。
4.3.2 添加 I2C 驱动
很多传感器、显示屏都挂在 I2C 总线上。进入:
Device Drivers --->
I2C support --->
I2C Hardware Bus support --->
<*> Synopsys DesignWare I2C adapter
这里要根据你的 SoC 型号来选择。比如全志的芯片通常用 DesignWare 的 I2C 控制器,而 STM32MP1 系列用的是 ST 自家的驱动。拿不准的话,去查芯片手册或者看内核源码里的 arch/arm/boot/dts/ 目录,设备树文件里会写明 compatible 属性。
4.4 删除不需要的驱动模块
添加驱动只是第一步。更重要的,其实是「做减法」。我见过不少新手,把内核配置里所有驱动都选上,结果编译出来的 zImage 有 20 多 MB,启动慢得像蜗牛。
举个例子,如果你的板子没有 WiFi 模块,那就把:
Device Drivers --->
Network device support --->
Wireless LAN --->
这一整项都取消掉。同理,没有蓝牙就关掉蓝牙驱动,没有 PCIe 就关掉 PCIe 支持。
注意:删除驱动时要小心。有些驱动是系统依赖的,比如 CONFIG_OF(设备树支持)就不能关,关了内核连设备树都解析不了。如果不确定某个选项的作用,按 ? 键查看帮助信息。
4.5 保存配置并退出
配置完成后,按 Tab 键选中 <Save>,回车。它会问你保存路径,默认是 .config,直接回车就行。然后选 <Exit> 退出。
这时候,Buildroot 会把你的配置保存到 output/build/linux-xxx/.config 里。下次再执行 make 时,它会直接用这个配置来编译内核。
4.6 一个小技巧:保存配置到 Buildroot 外部
我个人习惯把内核配置单独保存一份,方便以后复用。比如:
cp output/build/linux-5.10.24/.config board/mycompany/myboard/linux.config
然后在 Buildroot 的配置里指定:
BR2_LINUX_KERNEL_CUSTOM_CONFIG_FILE="board/mycompany/myboard/linux.config"
这样,就算你把 output 目录删了重来,内核配置也不会丢。我在项目里吃过这个亏——有一次不小心 make clean 把整个 output 清掉了,辛辛苦苦配了一下午的内核配置全没了。从那以后,我就养成了这个习惯。
4.7 本章知识体系
下面这张图,帮你理清内核配置的核心逻辑:
4.8 避坑指南
最后,分享几个我踩过的坑:
- 配置没保存就退出——这个最冤。界面里选了半天,结果退出时选了
<Exit>没选<Save>,白忙活。记住:先 Save,再 Exit。 - 依赖选项没选——比如你选了某个 USB 网卡驱动,但它依赖 USB 支持。如果你没开 USB 子系统,这个驱动虽然选上了,编译时也会报错。遇到这种情况,按
?查看依赖关系,把依赖项也勾上。 - 设备树和驱动不匹配——有时候驱动选对了,但设备树里对应的节点 status 是 "disabled"。这属于硬件描述层面的问题,跟内核配置无关。如果驱动加载不上,记得去检查设备树。
嗯,内核配置这部分就讲到这里。你跟着操作一遍,把板子需要的驱动都配好,然后就可以继续往下走了。
公众号:蓝海资料掘金营,微信deep3321