摘要
本文系统记录了我如何将树莓派 5 打造成主线 Linux 内核(Vanilla Kernel)的极简开发与测试平台——包括仓库极简裁剪思路、定制化内核配置、交叉编译与自动部署脚本、overlay 移除技巧,以及长期与主线社区同步维护的实战心得。适合关注 Linux 主线、ARM64 适配、内核开发、Upstream 贡献或喜欢折腾内核的极客们参考和实践。
背景与动机
最近一段时间,我在深入研究 Linux Kernel 的理论和架构,准备正式切入操作系统内核领域。因此,特意购买了树莓派 5 作为开发板,用于学习和实践内核开发。然而刚上手就发现,目前树莓派 5 并不能直接跑主线 Linux 内核,只能依赖树莓派团队维护的内核仓库。当时最新的分支是 rpi-6.14.y(现在是 rpi-6.16.y),仓库的维护方式是“动态拉取上游主线代码+rebase+大量自定义补丁”,涉及上万行的修改和历史反复变动。
这些定制补丁对于官方内核在树莓派上稳定运行、兼容所有功能确实非常重要,但对我这种纯粹想研究主线内核特性、关注内核本身的开发者来说,这些补丁反而变成了负担:
- 主线同步困难,merge 经常出冲突,
- 版本历史频繁重写,难以回溯和比较,
- 验证主线新特性或做反馈变得不直观。
我对比了 x86 开发板,发现它们大多能直接运行主线内核,但价格昂贵,性价比远不如树莓派 5。因此,我开始思考,如何让树莓派 5 也能顺畅运行主线内核,真正实现随时体验和测试内核最新特性,并为 ARM64 平台反馈问题、贡献补丁提供便利。我的目标很明确:用最少的补丁、最贴近 upstream 的方式,让树莓派 5 成为个人主线内核实验和学习的理想 ARM64 平台。
仓库结构与修改范围
我的做法十分简单却又直奔核心——只保留最必要的驱动与补丁,其余全部紧跟主线。仅对 drivers/ 目录做补丁,聚焦核心硬件支持,主要包括:
-
SD 卡驱动:保证树莓派能正常引导,内核能加载根文件系统。虽然启动固件自带部分初始化功能,但主线内核仍需驱动挂载根文件系统。
-
有线网卡(Ethernet):方便通过 SSH 实现远程登录、下载新内核镜像、远程开发和调试,是内核开发过程中最重要的 IO 通道之一。
-
UART 串口:作为内核调试和 early print 的输出窗口,可以直接观察内核日志,判断启动和运行状态。
-
USB 控制器:用于外部设备挂载或偶尔传输离线数据,兼容更多实验场景。
-
基本 GPIO、电源管理等与 RPi5 硬件紧密相关的部分。
-
剔除官方内核中与 Wi-Fi、蓝牙、GPU(VideoCore)、HDMI、音视频加速等非内核开发必需的子系统支持,这些对内核本身的研究和测试意义不大。
维护 arch/arm64/boot/dts/ 下的树莓派 5 DTS(Device Tree)配置
- 重点保证启动时能正确识别 RPi5 的各项硬件资源、CPU 配置和外设映射,确保主线内核能顺利运行。
其余全部与 Linus 主线保持 1:1 同步
- 除上述极少量补丁外,仓库其它部分完全保持与 官方主线仓库 一致。
- 定期(如每月或每两周)从主线拉取最新代码,只需应用极少量补丁并解决小范围冲突。
通过以上做法,仓库极简、易维护,也为后续的配置精简与快速主线跟进打下了基础。
定制化内核配置示例
在实际部署过程中,我为树莓派 5 主线内核准备了一套自定义 .config 配置文件,目标是在最大限度裁剪无关功能、最小化编译体积和时间的基础上,满足我个人的开发、测试与服务需求。这个过程也伴随着不断试错和优化。
第一阶段:极致裁剪,只留核心
最初版本的 .config 文件,几乎关掉了所有我认为不需要的驱动和功能模块,包括:
- 所有非板载网卡驱动(只保留树莓派 5 板载 Cadence 网卡驱动)
- 虚拟化支持(KVM 等)
- 图形子系统、声卡、HDMI、多媒体加速等
- 所有网络文件系统
- 除了 ext4 和 SD 卡(mmcblk)以外的文件系统
- 与上述模块相关的部分加密算法和内核机制
- 甚至关闭了 cgroup
经过几轮调试和实测,虽然最终配置未必是理论上“最精简”,但已经让内核编译时间大幅下降,同时可以稳定启动和完成我需要的基础功能。
第二阶段:实用扩展,支持 Docker 负载与日常服务
随着内核实验的深入,我意识到:
- 需要借助 Docker 跑一些实际负载以验证 kernel 的稳定性和兼容性;
- 需要支持局域网文件服务器(NAS)等日常场景;
- 还想用另一个树莓派长期运行自编译内核,部署不那么关键的服务。
因此,新的配置文件又逐步扩展了部分功能,如:
- cgroup、iptables、fuse、overlayfs、wireguard、macvlan、NFS、Samba 等常见内核模块(用于支持 Docker 及文件服务)
- 大多数新增特性编译为模块(module),按需加载,进一步优化启动和运行效率
这一步虽然让编译时间略有增加,但相比主线默认配置仍非常精简,也更贴合我的实际使用和验证需求。
配置文件仓库托管在: https://git.bktus.com/Linux/kernel-configs/
部分关键配置文件及时间线:
- eric-rpi-v1_defconfig
- eric-vanilla-c-6.13_defconfig
- eric-vanilla-c-6.14_defconfig
- eric-vanilla-c-6.15_defconfig
- eric-vanilla-v1_defconfig
- eric-vanilla-v2_defconfig
- eric-vanilla-v3_defconfig
可以通过这些配置文件,看到我从极致裁剪到逐步扩展的调试和优化历程。
优势与应用场景
贴近主线,快速体验和验证新特性
保持极简补丁的最大好处在于:你可以几乎“零成本”地将 linux-next 分支的最新补丁,乃至 Linus Merge Window 期间的新功能直接拉到 RPi5 上跑起来。无论是新调度器、文件系统新特性、虚拟化和安全子系统增强(如 KVM、eBPF、LSM),还是 Zstd 压缩、新的内存管理机制,只要主线有变化,你都能第一时间在真机上测试、验证其兼容性和性能表现,并及时为上游 ARM64 社区反馈问题和优化建议。
更重要的是,通过运行“香草”内核(Vanilla Kernel),你能最大程度还原和理解主线内核本身的实现逻辑,避免树莓派官方补丁引入的“副作用”,也不用担心误把 vendor patch 的问题当成主线 bug。
采用 merge 而非 rebase 的方式维护补丁,仓库历史更加清晰,主线与本地差异一目了然,每次合并主线几乎“秒通过”,让你能始终跟进内核最新开发进度——比如随时 pull linux-next 测试,或者 benchmark 内核新功能,体验感和参与感都极强。
这种方式对内核开发者、upstream 爱好者甚至“硬核”hacker 都非常有价值——你遇到的 bug、提交的 patch,就是主线环境下的真实问题,可以直接和内核社区无缝对接。
维护与开发更高效
- 补丁极少、冲突极少:只聚焦 RPi5 必需硬件支持,每次上游合并只需关注 drivers/net/arm/…、drivers/usb/…、drivers/bus/… 和 arch/arm64/boot/dts/broadcom/… 这几处,冲突极有限,维护量低。
- 调试与回滚极其方便:如果主线引入了回归或异常,只需排查极少补丁即可回退或调整,无需在成千上万行 vendor patch 里大海捞针。
- 便于贡献上游:你做的驱动补丁和 bug 修复非常“干净”,可直接整理成 patch,推送到 kernel mailing list,方便社区 review,不会因为 vendor patch 干扰而被卡住。
理想的开发、测试与学习平台
- 新特性探索与验证:RPi5 作为一台低成本、主流 ARM64 开发板,可以轻松测试 linux-next 或任意主线分支,为 upstream 社区贡献测试与反馈。
- 性能调优与驱动测试:可以做性能 benchmark、驱动优化、功耗实验等,评估主线新功能在 ARM64 上的真实表现。
- 教学与自学环境:对于学习 Linux 驱动、设备树和 HAL 的同学来说,极简环境最大限度减少“环境噪声”,专注理解主线驱动框架和硬件抽象。
官方仓库在驱动齐全性、厂商适配性方面占据绝对优势,适合需要“开箱即用、多媒体完整体验”的用户;而我的主线仓库则专注于“紧贴上游、简化维护、便于开发”的需求。如果你只是想用树莓派 5 看视频、玩游戏、运行 GUI 桌面,官方仓库或许更方便;但对于内核工程师、开发者或热衷实验的同学,“轻量化主线仓库”则能让你更专注于内核本身。
如何使用与贡献
理论上,树莓派 5 相比与树莓派 4 性能有了可观的提升,它自己来编译自己的内核是完全可以的,体验上也不错(内存大于 4GB 的情况下)。但是如果你需要进行内核或者内核模块开发,然后开启代码索引等能力的话,它的性能就不足了。
我还尝试过给它加上官方的 SSD Kit(512GB),虽然解决了 I/O 方面的吞吐问题,但最终还是遇到了 CPU 瓶颈,因为它只有 4 个 core!所以,如果你纯粹是需要一个可以跑的最新内核,并不经常编译,你可以在树莓派上编译安装。但是需要进行更进一步的开发调试的话,我还是强烈建议使用交叉编译,也就是在 PC 或者工作站(一般是 x86 平台)上编译内核和内核模块等,然后再通过网络拷贝到树莓派上(也通过 SD 卡实现)。比如,我的工作站有 12 个 core,跑编译时间缩短了好几倍(相对于 RPi5 的 4 个 core 来说)。所以,下面我就拿我用的交叉编译环境来举例子。
在此之前,你需要先安装 ARM64 的交叉编译环境。我建议安装 ccache 来进一步缩短重复编译的时间,如果你不想用 ccache 的话,那请去掉后续章节给出的所有命令中关于 ccache 的部分。
sudo apt install bc bison flex libssl-dev make libc6-dev libncurses5-dev
sudo apt install crossbuild-essential-arm64
sudo apt install ccache
克隆仓库并检出最新分支
我仓库是在我自己私有 Git 上的,但你可以使用我在 GitHub 的镜像。我会定期追踪 linus 的主线仓库并更新 main 分支。
git clone https://git.bktus.com/Linux/kernel-configs.git
git clone https://github.com/saturneric/linux
cd linux
git checkout main
注意:第一条命令是克隆我前面给出的内核配置文件仓库,所以注意后续配置不要再用树莓派团队提供的配置文件(启用了大量特性),这大概率会导致后续编译好的内核无法启动。
进行简单配置
你需要在 kernel-configs 仓库选取一个适合当前版本的配置文件,重命名为.config
,然后拷贝到内核仓库的根目录下。
cp ../kernel-configs/eric-vanilla-c-6.16_defconfig .config
你可以在我提供的配置基础上进一步裁减内核,或者增加功能。
make ARCH=arm64 CROSS_COMPILE="ccache aarch64-linux-gnu-" menuconfig
编译
在准备好交叉编译环境直接编译。根据你的具体配置和机器性能,实际编译时间长短不一。我自己的编译时间大概是 10 分钟左右。
make ARCH=arm64 CROSS_COMPILE="ccache aarch64-linux-gnu-" -j$(nproc)
拷贝内核和内核模块到树莓派
你可以使用我提供的脚本,方便快速地把刚刚编译好的内核镜像与内核模块传输到树莓派的默认用户的家目录下。强烈建议内核镜像与设备树不要和树莓派 5 的默认内核同名,使用类似 kernel-vanilla.c.img
和bcm2712d0-rpi-5-b.vanilla.c.dtb
这样的名字,这样即使出了什么问题,我们也可以通过配置文件快速切换回原来的可用内核或者设备树。另外,脚本用到的 rsync 需确保免密 SSH,建议提前配置好公钥。
#!/bin/bash
# ====== 可配置参数(请根据实际情况修改) ======
# 本地存放内核编译产物的目录
LOCAL_KERNEL_ARTIFACTS="./kernel-artifacts"
# 目标树莓派的 SSH 连接信息(如 [email protected])
REMOTE_HOST="[email protected]"
# 树莓派上的目标存放路径(建议使用绝对路径,如 /home/pi/kernel)
REMOTE_KERNEL_ARTIFACTS="/home/pi/kernel"
# 目标内核文件名(可自定义,默认 kernel_2712.img)
KERNEL_IMG="kernel-vanilla.c.img"
# 设备树文件名(可自定义)
DTB_FILE="bcm2712d0-rpi-5-b.vanilla.c.dtb"
DTB_SOURCE="arch/arm64/boot/dts/broadcom/bcm2712d0-rpi-5-b.dtb"
# ==============================================
set -e
echo ">>> 清理并准备本地目录 <<<"
rm -rf "$LOCAL_KERNEL_ARTIFACTS"
mkdir -p "$LOCAL_KERNEL_ARTIFACTS"
echo ">>> 安装内核模块到本地输出目录 <<<"
make ARCH=arm64 CROSS_COMPILE="aarch64-linux-gnu-" INSTALL_MOD_PATH="$LOCAL_KERNEL_ARTIFACTS" modules_install
echo ">>> 拷贝内核镜像和设备树 <<<"
cp -v -f arch/arm64/boot/Image.gz "$LOCAL_KERNEL_ARTIFACTS/$KERNEL_IMG"
cp -v -f "$DTB_SOURCE" "$LOCAL_KERNEL_ARTIFACTS/$DTB_FILE"
echo ">>> 上传内核产物至树莓派 <<<"
ssh "$REMOTE_HOST" "sudo mkdir -p $REMOTE_KERNEL_ARTIFACTS"
rsync -avz --progress --delete "$LOCAL_KERNEL_ARTIFACTS/" "$REMOTE_HOST:$REMOTE_KERNEL_ARTIFACTS"
echo ">>> 上传完成!你可以登录树莓派并配置/切换启动内核 <<<"
这样,在执行完脚本后,待会你要安装的所有文件都先拷贝到树莓派上了,但注意只是拷贝上面去而已,还没有真正应用这个新内核。
安装树莓派内核与内核模块
使用下面的脚本,你可以方便地将刚刚拷贝到树莓派上的文件(设备树、内核与内核模块)安装到预想的位置上。注意:该脚本涉及系统多个关键目录,请务必确认参数避免误删或者覆盖重要文件。
#!/bin/bash
# ==============================================
# RPi5 主线内核本地部署/刷机脚本
# 用于将内核镜像、设备树、内核模块,统一安装到 /boot 和 /lib/modules
# 请确保在树莓派上、且拥有 sudo 权限运行
# ==============================================
set -e
# ====== 可配置参数(请根据实际情况修改) ======
# 上传产物存放目录(刚才 rsync 下来的)
REMOTE_KERNEL_ARTIFACTS="/home/pi/kernel"
# 内核镜像名(和上一个上传脚本保持一致)
KERNEL_IMG="kernel-vanilla.c.img"
# 设备树文件名
DTB_FILE="bcm2712d0-rpi-5-b.vanilla.c.dtb"
# 内核镜像与设备树所在位置
BOOT_FIRMWARE_PATH="/boot/firmware"
# 内核模块实际安装目录(目标)
LIB_MODULES_PATH="/lib/modules"
# ==============================================
echo ">>> 1. 安装内核镜像和设备树 <<<"
sudo cp -v "$REMOTE_KERNEL_ARTIFACTS/$KERNEL_IMG" "$BOOT_FIRMWARE_PATH/$KERNEL_IMG"
sudo cp -v "$REMOTE_KERNEL_ARTIFACTS/$DTB_FILE" "$BOOT_FIRMWARE_PATH/$DTB_FILE"
echo ">>> 2. 设置镜像和 DTB 权限 <<<"
sudo chown root:root "$BOOT_FIRMWARE_PATH/$KERNEL_IMG" "$BOOT_FIRMWARE_PATH/$DTB_FILE"
sudo chmod 644 "$BOOT_FIRMWARE_PATH/$KERNEL_IMG" "$BOOT_FIRMWARE_PATH/$DTB_FILE"
echo ">>> 3. 安装内核模块 <<<"
# 会自动覆盖同版本号模块
sudo rsync -av --progress "$REMOTE_KERNEL_ARTIFACTS/lib/modules/" "$LIB_MODULES_PATH/"
echo ">>> 4. 设置内核模块权限 <<<"
sudo chown -R root:root "$LIB_MODULES_PATH/"
find "$LIB_MODULES_PATH/" -type d -exec sudo chmod 755 {} \;
find "$LIB_MODULES_PATH/" -type f -exec sudo chmod 644 {} \;
echo ">>> 内核与模块部署完成!如有需要请更新/boot/config.txt 指定新内核 <<<"
配置树莓派固件引导新内核
你需要编辑/boot/firmware/config.txt
来确保树莓派固件引导新的内核并传递相应的设备树,然后使用内核树,最主要是修改或添加下面的两行。
# DTB
device_tree=bcm2712d0-rpi-5-b.vanilla.c.dtb
# Kernel
kernel=kernel-vanilla.c.img
移除树莓派的 DTS Overlay 特性(并避免常见启动问题)
树莓派团队为其平台引入了 DTS Overlay 机制,这一设计允许在加载主设备树(Device Tree)时,根据固件或用户需求动态叠加额外的 overlay 片段,从而灵活开启/调整外设、参数或特性。比如,你为树莓派增加了某个新模块或功能,仅需配置一个 overlay 即可激活,非常方便。
然而,这套机制目前并不被主线 Linux 内核支持!
如果在 /boot/firmware/config.txt
开启了 overlay 相关配置,而 overlay 文件与主线内核设备树(DTB)版本不兼容,极易出现启动异常、设备识别失败等问题。这对于追求极简、纯主线内核体验的内核开发者来说,往往带来更多困扰而非便利。
处理思路
对我个人而言,DTS Overlay 的灵活性虽强,但主线内核并未原生支持,且对内核调试和纯粹环境带来很多干扰。因此我选择彻底移除 overlay 功能,只保留主设备树文件。这么做直接的副作用是:某些硬件参数(如 CPU 启动参数)原本依赖 overlay 机制注入,直接去掉 overlay 会导致树莓派无法正常启动。
解决办法:我通过直接将所需的 CPU 参数写入主设备树文件来绕过了这个问题。实际上,bcm2712d0-rpi-5-b.dtb 这份官方设备树文件就是为无 overlay 场景准备的,只要使用它作为主设备树,系统即可正常引导,无需任何 overlay。
如何移除 overlay 配置(操作指南)
编辑 /boot/firmware/config.txt,确保只设置 device_tree,并移除或注释所有 overlay 配置(如 dtoverlay= 相关行)。示例如下:
# 指定主设备树文件(建议直接使用 bcm2712d0-rpi-5-b.vanilla.c.dtb)
device_tree=bcm2712d0-rpi-5-b.vanilla.c.dtb
# 不加载任何 overlay
#dtoverlay=xxx # 请全部注释或删除
# 其它 overlay 自动检测功能建议关闭
camera_auto_detect=0
display_auto_detect=0
# 启动内核镜像
kernel=kernel-vanilla.c.img
检查其它与 overlay 相关的配置
- 推荐关闭 camera_auto_detect 和 display_auto_detect。
- 确认没有任何 dtoverlay= 配置项被启用。
重启树莓派
确保上述修改生效后,重启设备,系统将直接加载主设备树文件,不会再应用任何 overlay,从而最大程度保持主线内核的纯净性和可控性。如果后续没有任何问题的话,可以移除/boot/firmware/overlays
这个目录来节省空间,这也能确保后续启动如论如何都不会加载这些 overlay 导致环境污染。
推荐 config.txt 最小配置模板
# 仅指定主设备树和主线内核镜像
device_tree=bcm2712d0-rpi-5-b.vanilla.c.dtb
kernel=kernel-vanilla.c.img
# 关闭 overlay 自动检测
camera_auto_detect=0
display_auto_detect=0
# 其它通用参数可保留
disable_fw_kms_setup=1
arm_64bit=1
disable_overscan=1
arm_boost=1
提交补丁或 Issue
- 如果你在参考本文章操作时遇到任何问题,或者发现某个环节导致流程无法跑通,欢迎随时反馈。
- 如果你修复了某个兼容性问题,或在使用过程中发现了 bug,也欢迎直接提交 Issue,与我和其他使用者共同交流、完善项目。
- 如果你在本仓库基础上新增了硬件支持、做了性能优化,或移植了主线内核的新补丁,建议按照 scripts/format-patch.sh 生成标准化补丁,然后直接发往上游 Linux 内核 mailing list,推动改进被社区采纳。
GitHub 仓库地址: https://github.com/saturneric/linux
长期维护说明
本仓库和这篇文章都不是一次性的“快闪项目”。由于我将长期研究 Linux 内核和操作系统相关理论,会持续关注并跟进主线内核的每一次重大版本发布(包括 rc1 … rcX 等阶段性 release),并将关键改动和适配及时合入 main 分支。每次主线同步前,我都会先在我的工作站(Debian Testing)上编译然后在树莓派 5 上实机验证,确保仓库始终可用、流程通畅。
如果你也在用树莓派做主线内核开发,或遇到相关兼容性、适配问题,欢迎评论交流!也期待你加入主线内核社区,推动 ARM64 平台持续进步。