第14课:很好,到这里你已经学会了:
1.Layer
2.Recipe
3.Image
4.Package
5.SDK
6.BSP
7.Device Tree
8.Kernel Config(menuconfig)
下面进入 第14课:Kernel Patch 管理。
这一课是真正的 Linux BSP 工程师 每天都会做的工作。
第14课:Kernel Patch 管理
文章摘要:
本课详细讲解了在Yocto项目中如何规范管理Linux内核补丁。核心思想是不直接修改kernel-source源码,而是将所有修改制作成patch文件,通过BitBake自动应用。课程涵盖了从为什么不能直接修改tmp/work目录下的源码,到正确的patch管理流程,包括patch的生成、组织、应用顺序和管理原则。通过完整的实验步骤,演示了如何从修改内核源码、生成patch、配置bbappend文件到验证patch正确应用的完整工作流。这是所有Linux BSP厂商(NXP、TI、Intel、ST、Raspberry Pi等)都采用的标准化内核修改维护方法。
目标:
不修改 kernel-source,而是把所有修改做成 patch,让 BitBake 自动打补丁。
这是 Yocto 最推荐,也是所有 Linux BSP 厂商(NXP、TI、Intel、ST、Raspberry Pi 等)都采用的方法。
为什么不能直接改 kernel-source?
例如你以前这样做:
tmp/work-shared/raspberrypi2/kernel-source/
进入里面:
drivers/
然后
vim hello_driver.c
或者
vim bcm2709-rpi-2-b.dts
甚至
vim Makefile
虽然:
bitbake virtual/kernel
能够编译成功。
但是:
下一次
bitbake -c clean virtual/kernel
或者
bitbake -c cleansstate virtual/kernel
整个
tmp/
都会重新生成。
你的修改:
全部消失。
所以:
tmp/work 里面任何源码,都不要长期修改。
正确流程
永远应该是:
源码
↓
修改
↓
git diff
↓
patch
↓
放进 layer
↓
SRC_URI += file://xxx.patch
↓
BitBake 自动打补丁
这就是 Kernel Patch 管理。
整个目录
建议建立:
meta-myproduct
└── recipes-kernel
└── linux
├── linux-raspberrypi_%.bbappend
└── files
├── 0001-add-hello-driver.patch
├── 0002-fix-led.patch
└── 0003-add-dts.patch
真正项目里:
几十、
几百、
甚至上千个 patch。
patch 从哪里来?
例如修改:
drivers/misc/hello_driver.c
修改以前:
printk("Hello\n");
改成:
printk("Hello Yocto\n");
然后:
git diff
得到:
diff --git a/drivers/misc/hello_driver.c b/drivers/misc/hello_driver.c
@@
-printk("Hello\n");
+printk("Hello Yocto\n");
保存:
0001-print-yocto.patch
放到:
files/
即可。
bbappend
例如:
linux-raspberrypi_%.bbappend
写:
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI += " \
file://0001-print-yocto.patch \
"
编译:
bitbake virtual/kernel
BitBake:
解压源码
↓
自动 apply patch
↓
开始编译
整个过程完全自动。
patch 顺序
如果:
SRC_URI += "\
file://0001.patch \
file://0002.patch \
file://0003.patch \
"
就是:
0001
↓
0002
↓
0003
依次应用。
所以 patch 一般编号:
0001
0002
0003
...
0123
0456
patch 管理原则
一个 patch:
一个功能。
例如:
0001-add-driver.patch
只增加 Driver。
不要:
Driver
+
DTS
+
LED
+
I2C
+
SPI
全部混一起。
以后很难维护。
修改 DTS 怎么办?
完全一样。
修改:
arch/arm/boot/dts/broadcom/bcm2709-rpi-2-b.dts
然后:
git diff
生成:
0002-add-led-node.patch
放:
files/
bbappend:
SRC_URI += " \
file://0002-add-led-node.patch \
"
即可。
修改 Driver
例如:
drivers/i2c/
drivers/spi/
drivers/usb/
drivers/net/
drivers/gpio/
全部都是:
修改源码
↓
git diff
↓
patch
↓
bbappend
修改 Kconfig
例如:
drivers/misc/Kconfig
新增:
config HELLO_DRIVER
生成:
0003-kconfig.patch
同样放进去。
修改 Makefile
例如:
drivers/misc/Makefile
增加:
obj-$(CONFIG_HELLO_DRIVER)+=hello_driver.o
生成:
0004-makefile.patch
也是一样。
一个完整 BSP 的样子
meta-myproduct
└── recipes-kernel
└── linux
├── linux-raspberrypi_%.bbappend
└── files
├── 0001-add-driver.patch
├── 0002-kconfig.patch
├── 0003-makefile.patch
├── 0004-add-dts.patch
├── 0005-fix-clock.patch
├── 0006-fix-reset.patch
└── ...
真正的大型 BSP 都是这样维护内核修改的。
与上一课(linux-*.bbappend)的关系
上一课你已经学会了:
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI += " \
file://my-overlay.dts \
"
这一课只是把 普通文件 换成了 补丁文件:
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI += " \
file://0001-add-driver.patch \
file://0002-add-dts.patch \
"
因此,Kernel Patch 管理本质上就是利用 linux-*.bbappend 将补丁加入 SRC_URI,由 Yocto
在内核源码解压后自动应用。
本课实验(推荐)
建议不要使用一个简单的 printk 示例,而是基于你已经完成的 hello_driver 实验,完整体验一次真实的 BSP 开发流程:
1.在 tmp/work-shared/raspberrypi2/kernel-source 中修改 hello_driver.c(例如新增一条 printk)。
2.使用 Git 生成一个补丁(如 0001-update-hello-driver.patch)。
3.将补丁放到:
meta-myproduct/
└── recipes-kernel/linux/files/
4.在 linux-raspberrypi_%.bbappend 中加入:
FILESEXTRAPATHS:prepend := "${THISDIR}/files:"
SRC_URI += " \
file://0001-update-hello-driver.patch \
"
5.删除对 kernel-source 的手工修改,重新编译:
bitbake virtual/kernel
6.启动 Raspberry Pi,确认新的 printk 已经生效。
这样你就完成了从直接改源码到用补丁维护内核修改的完整迁移,这也是实际 Yocto BSP 项目中最常见、最规范的开发方式。
第一步:确认 Kernel Source 是 Git 仓库
先进入 kernel 源码目录:
cd ~/yocto/build-rpi2/tmp/work-shared/raspberrypi2/kernel-source
执行:
pwd
应该看到类似:
/home/xxx/yocto/build-rpi2/tmp/work-shared/raspberrypi2/kernel-source
然后执行:
git status
为什么先做这一步?
因为 Yocto 的 kernel source 一般都是 Git 仓库。
如果看到类似:
On branch ...
nothing to commit
说明后面的实验都可以直接使用:
git diff
或者
git format-patch
来生成补丁。
如果不是 Git 仓库,我们会换另一种生成 patch 的方式。
先不要进行下一步。
请执行:
cd ~/yocto/build-rpi2/tmp/work-shared/raspberrypi2/kernel-source
git status
输出结果:
On branch rpi-6.6.y
nothing to commit, working tree clean
第二步:定位函数
先不要修改。
执行:
sed -n '890,930p' drivers/char/random.c
第三步:修改源码
编辑文件:
vi drivers/char/random.c
找到:
void __init random_init(void)
{
unsigned long entropy = random_get_entropy();
修改为:
void __init random_init(void)
{
pr_info("Kernel Patch Demo: random_init() called\n");
unsigned long entropy = random_get_entropy();
保存退出。
为什么使用 pr_info()?
Linux 内核推荐使用:pr_info(…)
而不是:printk(KERN_INFO …)
两者都可以,但 pr_info() 更符合现代内核代码风格
第四步:确认修改成功
执行:
git diff
你应该能看到类似:
diff --git a/drivers/char/random.c b/drivers/char/random.c
index ...
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ ...
void __init random_init(void)
{
+ pr_info("Kernel Patch Demo: random_init() called\n");
+
unsigned long entropy = random_get_entropy();
第五步:生成 Patch
git diff > ~/yocto/meta-myproduct/recipes-kernel/linux/files/0001-random-init-demo.patch
再确认文件已经生成:ls -l ~/yocto/meta-myproduct/recipes-kernel/linux/files
第六步:修改 linux-raspberrypi_%.bbappend
请先查看它的内容:
cat ~/yocto/meta-myproduct/recipes-kernel/linux/linux-raspberrypi_%.bbappend
第七步:确认 Yocto 能看到 Patch
这是很多教程都会省略的一步,但在实际开发中非常重要。
执行:
bitbake -e virtual/kernel | grep "^SRC_URI="
看到:
SRC_URI="...
file://my.cfg
file://0001-random-init-demo.patch
第八步:重新编译 Kernel(验证 Patch)
由于你之前直接修改了 kernel-source,我们现在要让 Yocto 重新解压源码,并通过 Patch 来恢复这次修改。
- 先恢复源码
回到 kernel-source:
cd ~/yocto/build-rpi2/tmp/work-shared/raspberrypi2/kernel-source
确认还有修改:
git status
然后恢复:
git restore drivers/char/random.c
再确认:
git status
应该看到:
nothing to commit, working tree clean
为什么这么做?
因为如果源码已经包含了你的修改,BitBake 再应用 Patch 时,可能会提示:
Reversed (or previously applied) patch detected!
我们要验证的是:
不是靠手工改源码,而是靠 Patch 自动完成修改。
2. 清理 Kernel
回到 build 目录:cd ~/yocto/build-rpi2
执行:bitbake -c clean virtual/kernel
3. 重新编译
然后执行:bitbake virtual/kernel
第九步:验证 Patch 是否真正应用
编译完成后,请不要急着烧录镜像。
先执行下面两个命令:
cd ~/yocto/build-rpi2/tmp/work-shared/raspberrypi2/kernel-source/drivers/char
grep -n "Kernel Patch Demo" random.c
892: pr_info(“Kernel Patch Demo: random_init() called\n”);
就说明:
这条代码不是你手工修改的,而是 Yocto 在解压源码后,自动应用 0001-random-init-demo.patch 得到的。
这就是 Kernel Patch 管理的核心。
~/yocto/build-rpi2/tmp/work-shared/raspberrypi2/kernel-source/drivers/char/random.c
SRC_URI += “file://0001-random-init-demo.patch”
bitbake virtual/kernel 会修改 random.c

400

被折叠的 条评论
为什么被折叠?



