Linux 内核
简介
在 GitHub 上修改
Raspberry Pi 内核是 托管在 GitHub 上;更新滞后于上游 Linux内核。上游内核持续更新,而 Raspberry Pi 则将 Linux 内核的长期版本整合到 Raspberry Pi 内核中。我们在 raspberrypi/firmware中为每个长期发布的 Linux 内核生成一个 next
分支。经过广泛的测试和讨论后,我们会将每个 next
分支合并到我们版本库的主分支中。
更新
通常的树莓派操作系统 update process 会自动将内核更新到最新的稳定版本。如果你想尝试最新的不稳定测试内核,可以 手动更新。
构建内核
在 GitHub 上修改
操作系统随附的默认编译器和链接器被配置为构建在该操作系统上运行的可执行文件。 原生编译 使用这些默认编译器和链接器。交叉编译 是为运行编译过程的目标之外的目标编译代码的过程。
Raspberry Pi 内核的交叉编译允许你从 32 位操作系统构建 64 位内核,反之亦然。或者,你也可以从 Raspberry Pi 以外的设备交叉编译 32 位或 64 位 Raspberry Pi 内核。
下面的说明分为本地编译和交叉编译。选择适合你的情况的部分;虽然这两个过程有许多相同的步骤,但也有一些重要的区别。
下载内核源代码
在为任何目标构建之前,你都需要内核源代码。要获取内核源代码,你需要 Git。如果尚未安装 Git,请先在设备上安装:
$ sudo apt install git
接下来,下载最新 Raspberry Pi 内核的源代码:
$ git clone --depth=1 https://github.com/raspberrypi/linux
这可能需要几分钟时间。
Tip
|
上面的 要下载不带历史记录的其他分支,请在上述命令中添加
有关可用分支的完整列表,请参阅 https://github.com/raspberrypi/linux [the Raspberry Pi kernel repository]。 |
本地构建内核
本指南假设你的 Raspberry Pi 运行的是最新版本的 Raspberry Pi OS。
首先,安装构建依赖项:
$ sudo apt install bc bison flex libssl-dev make
构建配置
本节介绍如何在构建内核时应用默认配置。您还可以通过以下方式配置内核:
要准备默认配置,请根据您的 Raspberry Pi 型号运行下表中的相应命令。
Architecture | Model | Command |
---|---|---|
64-bit |
Raspberry Pi 3 |
|
Compute Module 3 |
||
Raspberry Pi 3+ |
||
Compute Module 3+ |
||
Raspberry Pi Zero 2 W |
||
Raspberry Pi 4 |
||
Pi 400 |
||
Compute Module 4 |
||
Compute Module 4S |
||
Raspberry Pi 5 |
|
|
Pi 500 |
||
Compute Module 5 |
||
32-bit |
Raspberry Pi 1 |
|
Compute Module 1 |
||
Zero |
||
Zero W |
||
Raspberry Pi 2 |
|
|
Raspberry Pi 3 |
||
Compute Module 3 |
||
Raspberry Pi 3+ |
||
Compute Module 3+ |
||
Zero 2 W |
||
Raspberry Pi 4 |
|
|
Pi 400 |
||
Compute Module 4 |
||
Compute Module 4S |
Note
|
4 系列设备上的 32 位 Raspberry Pi OS 发行版使用 32 位用户态域,但使用 64 位内核。要构建 32 位内核,请设置 |
使用 LOCALVERSION
自定义内核版本
为防止内核覆盖 /lib/modules
中的现有模块,并在 uname
输出中说明运行的是自己的内核,请调整 LOCALVERSION
。
要调整 LOCALVERSION
,请修改 .config
中的以下一行:
CONFIG_LOCALVERSION="-v7l-MY_CUSTOM_KERNEL"
Tip
|
你也可以在 General setup > Local version - append to kernel release 中使用 menuconfig 以图形方式更改此设置。有关 menuconfig 的更多信息,请参阅 内核配置说明。
|
构建
接下来,构建内核。这一步可能需要很长时间,取决于你的 Raspberry Pi 型号。
-
运行以下命令构建 64 位内核:
$ make -j6 Image.gz modules dtbs
-
运行以下命令构建 32 位内核:
$ make -j6 zImage modules dtbs
提示:在多核 Raspberry Pi 型号上, make -j<n>
选项可在不同内核之间分配工作。这会大大加快编译速度。运行 nproc
查看你有多少个处理器;我们建议使用处理器数量 1.5 倍的数字。
安装内核
接下来,将内核模块安装到启动介质上:
$ sudo make -j6 modules_install
然后,将内核和设备树 blobs 安装到启动分区,备份原始内核。
Tip
|
如果不想在运行此命令的 Raspberry Pi 上安装刚编译好的内核,可将编译好的内核复制到另一个启动介质的启动分区,而不是 /boot/firmware/ 。
|
安装 64 位内核:
-
运行以下命令创建当前内核的备份镜像,安装新的内核镜像、覆盖层、README,并卸载分区:
$ sudo cp /boot/firmware/$KERNEL.img /boot/firmware/$KERNEL-backup.img $ sudo cp arch/arm64/boot/Image.gz /boot/firmware/$KERNEL.img $ sudo cp arch/arm64/boot/dts/broadcom/*.dtb /boot/firmware/ $ sudo cp arch/arm64/boot/dts/overlays/*.dtb* /boot/firmware/overlays/ $ sudo cp arch/arm64/boot/dts/overlays/README /boot/firmware/overlays/
安装 32 位内核:
-
创建当前内核的备份,然后安装新的内核映像:
$ sudo cp /boot/firmware/$KERNEL.img /boot/firmware/$KERNEL-backup.img $ sudo cp arch/arm/boot/zImage /boot/firmware/$KERNEL.img
-
根据你的 内核版本,运行以下命令:
-
适用于 6.4 及以下版本的内核:
$ sudo cp arch/arm/boot/dts/*.dtb /boot/firmware/
-
适用于 6.5 及以上版本的内核:
$ sudo cp arch/arm/boot/dts/broadcom/*.dtb /boot/firmware/
-
-
最后,复制覆盖层和 README:
$ sudo cp arch/arm/boot/dts/overlays/*.dtb* /boot/firmware/overlays/ $ sudo cp arch/arm/boot/dts/overlays/README /boot/firmware/overlays/
最后,运行以下命令重启 Raspberry Pi 并运行新编译的内核:
$ sudo reboot
Tip
|
或者,用不同的文件名复制内核(如
将此方法与自定义的`LOCALVERSION` 相结合,可将自定义内核与系统管理的原版内核映像分开。有了这种安排,当你的内核无法启动时,你就可以迅速恢复到原版内核。 |
交叉编译内核
首先,你需要一台合适的 Linux 交叉编译主机。我们倾向于使用 Ubuntu;因为 Raspberry Pi OS 也是 Debian 发行版,所以编译命令也类似。
安装所需的依赖项和工具链
要构建用于交叉编译的源代码,请在设备上安装所需的依赖项。运行以下命令安装大部分依赖项:
$ sudo apt install bc bison flex libssl-dev make libc6-dev libncurses5-dev
然后,针对要构建的内核架构安装适当的工具链:
-
要安装 64 位工具链以构建 64 位内核,请运行以下命令:
$ sudo apt install crossbuild-essential-arm64
-
要安装 32 位工具链以构建 32 位内核,请运行以下命令:
$ sudo apt install crossbuild-essential-armhf
构建配置
本节介绍如何在构建内核时应用默认配置。您还可以通过以下方式配置内核:
输入以下命令以创建源文件和设备树文件:
Target Architecture | Target Model | Command |
---|---|---|
64-bit |
Raspberry Pi 3 |
|
Raspberry Pi Compute Module 3 |
||
Raspberry Pi 3+ |
||
Raspberry Pi Compute Module 3+ |
||
Raspberry Pi Zero 2 W |
||
Raspberry Pi 4 |
||
Raspberry Pi 400 |
||
Raspberry Pi Compute Module 4 |
||
Raspberry Pi Compute Module 4S |
||
Raspberry Pi 5 |
|
|
32-bit |
Raspberry Pi 1 |
|
Raspberry Pi Compute Module 1 |
||
Raspberry Pi Zero |
||
Raspberry Pi Zero W |
||
Raspberry Pi 2 |
|
|
Raspberry Pi 3 |
||
Raspberry Pi Compute Module 3 |
||
Raspberry Pi 3+ |
||
Raspberry Pi Compute Module 3+ |
||
Raspberry Pi Zero 2 W |
||
Raspberry Pi 4 |
|
|
Raspberry Pi 400 |
||
Raspberry Pi Compute Module 4 |
||
Raspberry Pi Compute Module 4S |
使用 LOCALVERSION
自定义内核版本
为防止内核覆盖 /lib/modules
中的现有模块,并在 uname
输出中说明运行的是自己的内核,请调整 LOCALVERSION
。
要调整 LOCALVERSION
,请修改 .config
中的以下一行:
CONFIG_LOCALVERSION="-v7l-MY_CUSTOM_KERNEL"
Tip
|
你也可以在 General setup > Local version - append to kernel release 中使用 menuconfig 以图形方式更改这一设置。有关 menuconfig 的更多信息,请参阅 内核配置说明。
|
Build
-
运行以下命令构建 64 位内核:
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image modules dtbs
-
运行以下命令构建 32 位内核:
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage modules dtbs
安装内核
创建内核后,您需要将其复制到 Raspberry Pi 启动介质(可能是 SD 卡或 SSD)上,然后安装模块。
查找启动介质
首先,运行 lsblk
。然后,连接启动媒体。再次运行 lsblk
;新设备代表启动介质。你应该会看到类似下面的输出:
sdb sdb1 sdb2
如果 sdb
代表启动介质,则 sdb1
代表 FAT32
格式的 启动分区,而 sdb2
代表(可能是 ext4
格式的)根分区。
首先,将这些分区挂载为 mnt/boot
和 mnt/root
,调整分区代号以匹配启动介质的位置:
$ mkdir mnt
$ mkdir mnt/boot
$ mkdir mnt/root
$ sudo mount /dev/sdb1 mnt/boot
$ sudo mount /dev/sdb2 mnt/root
安装
接下来,将内核模块安装到启动介质上:
-
对于 64 位内核:
$ sudo env PATH=$PATH make -j12 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- INSTALL_MOD_PATH=mnt/root modules_install
-
对于 32 位内核:
$ sudo env PATH=$PATH make -j12 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=mnt/root modules_install
Tip
|
在多核设备上, make -j<n> 选项可在各核之间分配工作。这会大大加快编译速度。运行 nproc 查看你有多少个处理器;我们建议使用处理器数量的 1.5 倍。
|
接下来,将内核和设备树 blob 安装到启动分区,并备份原始内核。
安装 64 位内核:
-
运行以下命令创建当前内核的备份镜像,安装新的内核镜像、覆盖层、README,并卸载分区:
$ sudo cp mnt/boot/$KERNEL.img mnt/boot/$KERNEL-backup.img $ sudo cp arch/arm64/boot/Image mnt/boot/$KERNEL.img $ sudo cp arch/arm64/boot/dts/broadcom/*.dtb mnt/boot/ $ sudo cp arch/arm64/boot/dts/overlays/*.dtb* mnt/boot/overlays/ $ sudo cp arch/arm64/boot/dts/overlays/README mnt/boot/overlays/ $ sudo umount mnt/boot $ sudo umount mnt/root
安装 32 位内核:
-
运行以下命令创建当前内核的备份镜像,并安装新的内核镜像:
$ sudo cp mnt/boot/$KERNEL.img mnt/boot/$KERNEL-backup.img $ sudo cp arch/arm/boot/zImage mnt/boot/$KERNEL.img
-
根据你的 内核版本,运行以下命令安装设备树 blobs:
-
适用于 6.4 及以下版本的内核:
$ sudo cp arch/arm/boot/dts/*.dtb mnt/boot/
-
适用于 6.5 及以上版本的内核:
$ sudo cp arch/arm/boot/dts/broadcom/*.dtb mnt/boot/
-
-
最后,安装覆盖层和 README,并卸载分区:
$ sudo cp arch/arm/boot/dts/overlays/*.dtb* mnt/boot/overlays/ $ sudo cp arch/arm/boot/dts/overlays/README mnt/boot/overlays/ $ sudo umount mnt/boot $ sudo umount mnt/root
最后,将启动媒体连接到 Raspberry Pi,并接通电源,运行新编译的内核。
Tip
|
或者,用不同的文件名复制内核(如
将此方法与自定义的 |
配置内核
在 GitHub 上修改
The Linux kernel is highly configurable. Advanced users may wish to modify the default configuration to customise it to their needs, such as enabling a new or experimental network protocol, or enabling support for new hardware.
配置通常通过 make menuconfig
界面完成。另外,您也可以手动修改 .config
文件,但这可能比较困难。
menuconfig
设置好一切后,就可以编译并运行 menuconfig
实用程序,具体操作如下:
$ make menuconfig
交叉编译 64 位内核:
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
交叉编译 32 位内核:
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
要浏览 menuconfig
实用程序,请使用键盘:
-
要按方向导航,请使用 方向键。
-
要进入子菜单(用
--->
表示),请按 Enter 键 -
要上一级或退出,按两次 Escape 键
-
要切换二进制选项的状态,按 空格键。
-
选择多选选项的状态,按 Enter 键打开子菜单,按 方向键 浏览子菜单,再按 Enter 键选择状态
-
要获得选项或菜单的帮助,请按 H 键
简短编译后,menuconfig
会显示一个子菜单列表,其中包含所有可以配置的选项。选项很多,请慢慢阅读。第一次尝试时,不要轻易启用或禁用大量选项;这样很容易破坏配置,所以要从小处着手,熟悉配置和编译过程。
给内核打补丁
在 GitHub 上修改
在构建自定义内核时,您可能希望将补丁或补丁集合(补丁集)应用到 Linux 内核中。
硬件制造商有时会在补丁进入 Linux 内核和 Raspberry Pi 内核之前提供补丁集,作为支持新硬件的临时措施。不过,也有用于其他目的的补丁集,例如,用于实时使用的完全抢占式内核。
确定内核版本
要检查设备上当前运行的内核版本,请运行以下命令:
$ uname -r
打补丁前一定要检查内核版本。在内核源代码目录下,运行以下命令查看内核版本:
$ head Makefile -n 4
您应该会看到类似下面的输出:
# SPDX-License-Identifier: GPL-2.0 VERSION = 6 PATCHLEVEL = 1 SUBLEVEL = 38
在这个例子中,源代码是 6.1.38 内核。
打补丁
补丁的应用取决于补丁的分发格式。
开发人员会以单个文件的形式分发大多数补丁。使用 patch
实用程序应用这些补丁。以下命令将下载、解压缩并使用实时内核补丁为我们的示例内核版本打上补丁:
$ wget https://www.kernel.org/pub/linux/kernel/projects/rt/6.1/patch-6.1.38-rt13-rc1.patch.gz
$ gunzip patch-6.1.38-rt13-rc1.patch.gz
$ cat patch-6.1.38-rt13-rc1.patch | patch -p1
有些开发者会以 mailbox format 发布补丁,即一个包含多个补丁文件的文件夹。使用 Git 可以打上这些补丁。
Note
|
在使用 Git 应用 Mailbox 格式的补丁之前,请先配置您本地 Git 安装的用户名和电子邮箱:
|
要使用 Git 应用采用 Mailbox 格式的补丁,请运行以下命令:
$ git am -3 /path/to/patches/*
请始终遵循补丁分发者提供的说明。例如,有些补丁集要求针对特定提交打补丁。
Kernel headers
在 GitHub 上修改
要编译内核模块,你需要 Linux 内核头文件。这些头文件提供了编译与内核接口的代码所需的函数和结构定义。
如果你从 GitHub 克隆了整个内核,那么源代码树中已经包含了头文件。如果你不需要所有额外的文件,可以使用 apt
只安装内核头文件。
Tip
|
当新内核发布时,你需要与该内核版本相匹配的头文件。更新 apt 软件包以反映最新内核版本可能需要数周时间。有关最新的头文件版本,请参阅 克隆内核。
|
如果你使用的是 64 位版本的 Raspberry Pi OS,请运行以下命令安装内核头文件:
$ sudo apt install linux-headers-rpi-v8
如果您使用的是 32 位版本的 Raspberry Pi OS,请运行以下命令安装内核头:
$ sudo apt install linux-headers-rpi-{v6,v7,v7l}
Note
|
安装可能需要几分钟。没有进度指示器。 |
贡献
在 GitHub 上修改
您可能出于多种原因希望向内核中添加内容:
-
您编写了一些树莓派专用代码,希望所有人都能从中受益
-
你为某个设备编写了通用的 Linux 内核驱动程序,并希望每个人都能使用它
-
你修复了一个通用内核错误
-
你修复了一个树莓派特有的内核错误
如果是针对 Raspberry Pi 的更改或错误修复,请向 Raspberry Pi 内核提交拉取请求。 对于一般的 Linux 内核更改(如新驱动程序),请先向上游 Linux 内核提交拉取请求。一旦 Linux 内核接受了您的更改,我们就会收到。
为 Raspberry Pi 内核做贡献
首先,fork Raspberry Pi 内核资源库并克隆到你的开发设备上。然后,您可以进行修改、测试并提交到您的 fork 中。
然后,向 Raspberry Pi 内核资源库提交包含你的修改的拉取请求。Raspberry Pi 工程师将审核您的贡献并提出改进建议。一旦获得批准,我们就会合并您的修改,最终将它们添加到 Raspberry Pi 内核的稳定版本中。
为 Linux 内核做贡献
首先,将 Linux 内核树克隆到你的开发设备上。然后,你就可以进行修改、测试并提交到本地树中。
修改完成后,你就可以提交给 Linux 内核社区了。Linux 内核开发是在邮件列表而非 GitHub 上进行的。为了让你的修改成为 Linux 的一部分,请将其作为补丁通过电子邮件发送给社区。请遵循 Linux 内核文档中的 提交补丁:将代码加入内核的基本指南 和 Linux 内核编码风格。 Linux 内核贡献者会审查你的贡献并提出改进建议。一旦获得批准,他们就会合并你的修改。最终,这些改动将被纳入 Linux 内核的长期版本中。一旦我们测试了该长期版本与 Raspberry Pi 内核的兼容性,您的修改就会进入 Raspberry Pi 内核的稳定版本。