简介这是一份树莓派 Linux 内核 4.19.y 分支的完整源码包面向嵌入式开发者、树莓派爱好者和内核学习人员可满足内核定制、驱动编写、系统调优、交叉编译和底层原理研究等需求。压缩包为 zip 格式共包含约 2000 个文件整体大小约 193.93MB文件类型以 C 语言源码、头文件为主同时涵盖 Makefile 构建脚本、DTS 设备树文件、Kconfig 配置选项以及少量文档和辅助脚本共同构成了一套完整的 Linux 内核开发支持体系。目前已有 597 人浏览学习。通过研读这套源码读者能够理解树莓派硬件与内核各子系统的对应关系掌握设备树对板级硬件配置的作用并参考其中的驱动实现来编写自定义驱动或根据实际需求配置裁剪内核功能。对于希望深入 Linux 内核底层、开展嵌入式系统开发实践的人来说这是一份兼具理论深度和实用价值的基础资料。1. 树莓派linux源码4.19.y为什么这个老内核分支到今天还有人在追“树莓派linux源码版本4.19.y”光看这个名字很容易把它和 Linux 主线仓库里那个 4.19.y 的 tag 混为一谈。真正做产品的人知道区别在哪树莓派官方在主线 4.19.y 之上叠了一层自己的补丁集GPU 显示栈、DWC2 USB、设备树 overlay、GPIO 复用逻辑全在这层补丁里。很多在 4.19.y 上稳定跑了好几年的老驱动升到 5.x 之后反而没人维护了反过来不少第三方传感器和板级驱动只在 4.19.y 上验证过。所以做内核编译、驱动适配、镜像定制和老设备维护的人手上必须有一条拿来就能用的 4.19.y 官方分支。这篇我从拿对源码讲起一路到配置、编译、设备树最后把最容易踩的坑按现象列给你。2. 拿对分支与源码树莓派官方不是直接用 linus 的 4.19.y第一次动手前我一般会先讲清楚为什么不能拿主线源码来凑合。树莓派的 4.19.y 分支不是简单改了版本号它带着一套独立维护的补丁基线。主线 Linux 的 4.19.y tag 里只有通用驱动没有树莓派那套 BCM2835/2836/2837/2711 的外设支持也没有 VC4 GPU 开源驱动的后续修复。最直接的例子主线 4.19.y 里 ARCH_BCM2835 的菜单组织和树莓派分支完全不同用主线的 defconfig 编出来的 zImage放到树莓派上就算能启动USB、SD 卡、GPIO 的行为也会和官方固件预期不一致。所以只有两条路要么直接拉官方维护的源码要么把官方补丁手工合进主线树。后者工作量巨大而且每次主线更新都要重合一遍我试过两次就放弃了。常见做法是直接拉官方分支成本最低后面改设备树、编驱动模块都在同一棵树上做不会出现版本错位的问题。2.1 两棵树不能混官方 rpi 分支与 vanilla 主线的关系树莓派官方会同时维护多条内核分支4.19.y 是其中一个长期维护线。它现在看起来老但在工控设备和定制产品里生命周期非常长原因是它把稳定性和新驱动放在一个相对平衡的位置上。官方分支里有很多主线没有或不完整的驱动目录比如 VC4 GPU、V3D、DWC2 的树莓派定制部分这些在主线里往往只到“能编译”的程度距离“在板子上稳定工作”还有距离。我见过有人拿 vanilla 主线的 4.19.y tag 编出来启动后网络不通、USB 识别异常查了半天发现是驱动差异不是配置问题。对外设驱动开发来说必须在官方 rpi-4.19.y 上开自己的开发分支否则后面合并补丁会合到怀疑人生。官方分支的提交历史里能明显看到“bcm2711”“bcm2835”“vc4”这些关键词这是判断你拉对树的一个信号。2.2 拉源码的最小命令git clone 的三个参数坑# 拉取官方 4.19.y 分支仓库地址换成团队内能访问的镜像即可 RASPI_REPO你的镜像地址/linux.git git clone --depth1 --branch rpi-4.19.y ${RASPI_REPO} raspberrypi-linux cd raspberrypi-linux git log --oneline -1--depth1只拉最浅历史好处是省带宽代价是后面想切换其他 tag 或者用git describe做版本判断时会缺少必要的提交信息。我一般首次拉取不加深度的限制日常同步增量更新时才用--depth1。--branch rpi-4.19.y是最关键的参数很多第一次拉的人写成4.19.y结果拉到的是主线 tag目录结构和驱动补丁对不上编到一半才发觉。仓库地址替换成你团队内能访问的官方源码镜像只要带rpi-4.19.y分支就行。拉完以后先确认分支状态git branch -a | grep 4.19 git log --oneline -1注意官方仓库当前默认分支不是 4.19.y直接git clone不带--branch会拉到更新的维护分支那个分支的补丁基线和 4.19.y 不同不适合复现 4.19.y 环境。所以分支名必须写全。2.3 源码树里值得先看的四个目录目录看什么arch/arm/configs板级 defconfigbcmrpi_defconfig、bcm2709_defconfig、bcm2711_defconfigarch/arm/boot/dts/overlays所有 overlay 的 dts 源文件和编译产物 dtbodrivers/gpu/drm/vc4GPU 显示相关驱动4.19.y 上比较稳定Documentation/devicetree/bindings写新 overlay 时对照属性名和节点格式这四个目录基本划出了整棵树的边界。看到一个设备树属性不确定对不对去 bindings 里查看到一个外设没反应去 overlays 里找有没有对应 dtbo。4.19.y 的 overlay 机制在文档里写得比较完整新内核反而把 overlay helper 重构过老资料不一定能对上新写法。3. 配置与编译全流程从 defconfig 到能跑的内核镜像源码拿到后下一步是配置和编译。这一步失误率最高因为很多人沿用主线内核的习惯直接make defconfig编出来的东西放到树莓派上经常起不来。4.19.y 的官方源码里给每一代板子都准备了独立 defconfig选对板型配置比后续手调参数重要得多。3.1 配置三选一板级 defconfig、menuconfig 与自定义 configcd raspberrypi-linux make ARCHarm bcm2711_defconfig make ARCHarm menuconfig第一行根据板型选择树莓派 1 用bcmrpi_defconfig树莓派 2/3 用bcm2709_defconfig树莓派 4 用bcm2711_defconfig。第二行是打开交互式配置界面在板级配置之上做微调比如加文件系统支持、去掉用不到的驱动。menuconfig 保存后生成的是全量.config不是增量补丁但建议用savedefconfig把缩略配置单独存一份方便以后重新生成make ARCHarm savedefconfig cp defconfig arch/arm/configs/raspberrypi_my_defconfig这样以后直接make ARCHarm raspberrypi_my_defconfig就能回到当前状态不用再手动点一遍菜单。我自己的习惯是每调完一组配置就存一次相当于给内核配置做版本备份。3.2 交叉编译还是板端编译先算时间账在树莓派 4 上全量编译 4.19.y快则四五十分钟慢则一个多小时交叉编译一般十几分钟就能出 zImage。常见做法是准备一台 Linux 开发机装 armhf 工具链。Ubuntu/Debian 系可以用包管理器直接装装完先验证arm-linux-gnueabihf-gcc --version aarch64-linux-gnu-gcc --version有版本输出说明工具链可用。一个容易忽略的点是工具链的 glibc 版本不能太新部分发行版自带的工具链在编老内核时会出现隐式函数声明之类的错误后面排错章节会细说。我先给推荐的最小环境变量export ARCHarm export CROSS_COMPILEarm-linux-gnueabihf- export KERNELkernel7ARCHarm表示编 32 位内核对应 32 位用户空间如果做 64 位改成ARCHarm64、CROSS_COMPILEaarch64-linux-gnu-镜像名对应kernel8。KERNEL变量在最后打包时用提前设好省得每次敲。3.3 最小编译命令与输出物落盘make -j4 zImage modules dtbs mkdir -p /tmp/pi-modules make INSTALL_MOD_PATH/tmp/pi-modules modules_install ls /tmp/pi-modules/lib/modules/zImage是内核本体modules是外设驱动模块dtbs是设备树二进制。INSTALL_MOD_PATH指定模块安装目录这是我一直推荐的做法不要把模块直接装到开发机的/lib/modules既不污染本机拷到板子也方便。编译完成后确认产物ls arch/arm/boot/zImage ls arch/arm/boot/dts/bcm2711-rpi-4-b.dtb ls arch/arm/boot/dts/overlays/*.dtbo把这几个文件同步到 SD 卡时要注意zImage 通常要经过一个打包步骤变成kernel7.img常见做法是用树莓派固件里的mkknlimg处理如果你的固件版本支持直接从/boot加载 zImage也可以跳过这个步骤。设备树文件建议整目录覆盖不要只拷一个 dtb因为启动时固件会按 config.txt 的配置读取对应 dtbo新旧版本混用会导致外设行为异常。注意很多人只换内核不换 overlay新旧 dtbo 和内核里的设备树解析接口不匹配系统起来后 USB 或 GPIO 表现得很奇怪这不是驱动问题是设备树版本不一致。4. 设备树与 overlay4.19.y 上最容易出事的两个大头编译通过只算走完一半。树莓派体系里最特殊的是设备树 overlay 机制4.19.y 上要驱动某个外设三分靠内核配置七分靠设备树。很多新手改完 config.txt 发现没生效回头查代码其实是 overlay 没对上或没被正确加载。4.1 overlay 的编译与装载config.txt 一行背后的机制overlay 的源文件在arch/arm/boot/dts/overlays/目录下命名一般是xxx-overlay.dts编译后生成xxx.dtbo放到板子的/boot/overlays/目录。启动时固件读取/boot/config.txt遇到dtoverlayxxx就加载对应的 dtbo 并合并进系统设备树。make ARCHarm dtbs sudo cp arch/arm/boot/dts/overlays/*.dtbo /boot/overlays/config.txt 里的写法# 启用自定义 overlay不带 .dtbo 后缀 dtoverlaymy-overlay拷贝时别只拷单个文件因为一个外设的 overlay 经常依赖其他基础 overlay只拷一部分会导致依赖缺失启动日志里只留一条含糊的“failed to apply”消息。dtbo 文件名不带后缀config.txt 里不能写成my-overlay.dtbo多写个后缀反而找不到文件。4.2 验证驱动是否加载三件套设备树和内核有没有真正配合上用下面三条命令查最快cat /proc/device-tree/model dmesg | grep -E overlay|dwc2|vc4|bcm ls /sys/bus/platform/devices/第一条看系统识别的板型如果显示的内容和你手里的板子对得上说明基础设备树没问题第二条看驱动 probe 日志能直接看到哪个驱动加载失败、失败原因是找不到中断号还是地址冲突第三条看平台设备节点有没有生成节点存在但驱动没 probe问题在内核配置节点本身不存在问题在 overlay 没合入。这个排查顺序能帮你把问题快速定位到设备树层还是驱动层。4.3 在 4.19.y 上二次开发三个边界第一个边界是设备树语法。4.19.y 的 overlay 写法和主线基本一致但 fragment 的组织方式有一套固定套路建议从现有 overlay 复制后修改而不是从零手写能省掉大量语法错误。第二个边界是驱动模块必须在同一棵源码树编译把主线 Linux 源码编出来的 .ko 塞到树莓派 4.19.y 系统里多半会报 version magic mismatch模块直接被拒绝加载。第三个边界是新增节点一定要在编译阶段验证语法make dtbs 报错时不要跳过否则启动时 overlay 会静默失败。单独编一个模块的标准做法make ARCHarm Mdrivers/net/ethernet/some-driver modulesM指向驱动子目录编出来的.ko拷贝到板子的/lib/modules/$(uname -r)/extra/下执行depmod -a再加载。4.19.y 分支对M的 Kbuild 支持很完整这个流程比改整个内核快得多。5. 树莓派 4.19.y 编译路上最常翻的 5 个车这章写几个我实际遇到过的现象每条按“现象 → 原因 → 解决”列出你在自己机器上对号入座就行。5.1 menuconfig 保存后行为没变现象改了内核配置并保存重新编译烧录跑起来的行为和之前一模一样好像配置没生效。 原因编译目录里有旧的.config残留或者make clean把配置清了但菜单里保存的是默认值。更隐蔽的情况是改了内核选项但没重新编 modules旧模块还在 rootfs 里驱动照样加载老版本。 解决先彻底清理再重新走一遍make mrproper make ARCHarm bcm2711_defconfig make ARCHarm menuconfig make -j4 zImage modules dtbs改配置前先备份一份.configcp .config .config.bak这是最保险的后悔药。5.2 启动卡在 VFS: Unable to mount root fs现象内核启动到一半控制台输出VFS: Unable to mount root fs然后直接 panic。 原因rootfs 里没有对应内核版本的/lib/modules或者根文件系统驱动被编成了模块而不是编进内核。4.19.y 默认配置里 EXT4 通常是编进内核的但如果你在 menuconfig 里改过文件系统选项容易把它改成m。 解决确认.config里CONFIG_EXT4_FSy而不是m。如果是模块方式就必须准备 initramfs 来加载模块否则内核根本找不到根文件系统。5.3 设备树 overlay 改了没反应现象在 config.txt 里加了dtoverlayxxx重启后设备节点不存在外设没被驱动。 原因dtbo 没拷到/boot/overlays/config.txt 里拼写带了.dtbo后缀或者文件拷完没有 sync 就直接拔卡。boot 分区是 vfat拷贝后缓存没落盘重启就丢。 解决ls /boot/overlays/ | grep my-overlay cat /boot/config.txt确认文件名和后缀之后重新拷贝并执行sync再重启验证。5.4 insmod 报 invalid module format 或 version magic mismatch现象模块编译成功后拷到板子insmod直接拒绝加载提示 version magic mismatch。 原因系统跑的是 64 位内核编译环境却用ARCHarm编了 32 位模块或者板子系统内核版本和编译源码树版本不一致。 解决先看系统内核版本和模块的 vermagic 是否一致uname -r modinfo xxx.ko | grep vermagic两者必须完全对应。模块一定要在跑着 4.19.y 的那同一个源码分支上编译不能拿主线 4.19.y tag 的源码树来编。5.5 编译到 drivers/gpu/drm/vc4 附近报错现象编译进度走到drivers/gpu/drm/vc4或drivers/staging/vc04_services时报错错误信息看着像语法问题但代码本身没改过。 原因源码树不完整之前中断的 clone 或 fetch 留下了缺失文件或者工作目录里混入了之前 make 产生的中间产物。 解决先检查目录状态再干净重编git status git fetch make clean make -j4 zImage modules dtbs如果git status显示大量修改文件说明编译产物污染了源码目录先make clean再继续。6. 验证与反哺把 4.19.y 用顺手的几个小习惯6.1 用 make savedefconfig 管好内核配置make ARCHarm savedefconfig cp defconfig arch/arm/configs/某一板型_defconfig这个命令把当前.config缩成一个最小可读配置以后直接make 某一板型_defconfig就能回到当时的状态。它比备份整个.config文件更干净也更容易用 diff 工具对比配置差异。我在 4.19.y 上改配置前一定会先跑一次这个命令。6.2 升级内核前备份模块目录sudo cp -r /lib/modules/$(uname -r) /lib/modules/$(uname -r).bak把自编译模块放到/lib/modules/$(uname -r)/extra/然后执行depmod -a。系统起不来时切回备份模块目录比重新编译快得多。这个习惯在很多内核版本上都通用但在 4.19.y 这种需要长期维护的分支上尤其有用。6.3 交叉编译的验证节奏交叉编译十几分钟就能出一版板端编一次够交叉编三轮。我的一般节奏是改一批配置或驱动就编一次先看 zImage 和 dtbs 是否通过再编 modules最后统一拷到 SD 卡。验证时先看启动日志里的 probe 消息再看/sys/bus/platform/devices/里有没有新设备节点而不是直接测外设功能能节省大量排查时间。在我自己的习惯里4.19.y 这类分支最怕的不是内核老而是你对它不够熟。老内核的资料多、踩过坑的人也多几乎每个报错都能找到对应记录。真正让我吃过亏的反而是改 menuconfig 没存盘就重启编出来的内核行为跟预期差很远最后只能重新来。从那以后每次动配置前的第一件事就是跑一遍make savedefconfig。这个方法也分享给你希望帮到你。本文还有配套的精品资源点击获取