Linux 内核

简介

Raspberry Pi 内核是 托管在 GitHub 上;更新滞后于上游 Linux内核。上游内核持续更新,而 Raspberry Pi 则将 Linux 内核的 长期版本 整合到 Raspberry Pi 内核中。我们在 raspberrypi/firmware中为每个长期发布的 Linux 内核生成一个 next 分支。经过广泛的测试和讨论后,我们会将每个 next 分支合并到我们版本库的主分支中。

更新

通常的树莓派操作系统 更新程序 会自动将内核更新到最新的稳定版本。如果你想尝试最新的不稳定测试内核,可以 手动更新

构建内核

操作系统预装的默认编译器和链接器被配置为构建在该操作系统上运行的可执行文件。 原生编译 使用这些默认编译器和链接器。交叉编译 是为运行编译过程的目标之外的目标编译代码的过程。

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

上面的 git clone 命令下载的是当前活动分支,我们从该分支构建 Raspberry Pi 操作系统映像,不包含任何历史记录。省略 `--depth=1`可以下载整个版本库,包括所有分支的完整历史。这需要更长的时间,占用的存储空间也更大。

要下载不带历史记录的其他分支,请在上述命令中添加 --branch 选项,并将 <branch> 替换为要下载的分支名称:

$ git clone --depth=1 --branch <branch> https://github.com/raspberrypi/linux

有关可用分支的完整列表,请查看 树莓派内核库

现在你有了内核源代码,请通过 本机交叉编译 构建一个新内核。

本地构建内核

本指南假设你的 Raspberry Pi 运行的是最新版本的 Raspberry Pi OS

首先,安装构建依赖项:

$ sudo apt install bc bison flex libssl-dev make

构建配置

本节介绍如何在构建内核时应用默认配置。您还可以通过以下方式配置内核:

要准备默认配置,请根据您的 Raspberry Pi 型号运行下表中的相应命令。

架构 型号 命令

64-bit

Raspberry Pi 3

$ cd linux
$ KERNEL=kernel8
$ make bcm2711_defconfig

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

$ cd linux
$ KERNEL=kernel_2712
$ make bcm2712_defconfig

Pi 500

Compute Module 5

32-bit

Raspberry Pi 1

$ cd linux
$ KERNEL=kernel
$ make bcmrpi_defconfig

Compute Module 1

Zero

Zero W

Raspberry Pi 2

$ cd linux
$ KERNEL=kernel7
$ make bcm2709_defconfig

Raspberry Pi 3

Compute Module 3

Raspberry Pi 3+

Compute Module 3+

Zero 2 W

Raspberry Pi 4

$ cd linux
$ KERNEL=kernel7l
$ make bcm2711_defconfig

Pi 400

Compute Module 4

Compute Module 4S

Note

4 系列设备上的 32 位 Raspberry Pi OS 发行版使用 32 位用户态域,但使用 64 位内核。要构建 32 位内核,请设置 ARCH=arm。要启动 32 位内核,请在 config.txt 中设置 arm_64bit=0

使用 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 位内核:

  • 运行以下命令创建当前内核的备份镜像,安装新的内核镜像、overlays、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 位内核:

  1. 创建当前内核的备份,然后安装新的内核映像:

    $ sudo cp /boot/firmware/$KERNEL.img /boot/firmware/$KERNEL-backup.img
    $ sudo cp arch/arm/boot/zImage /boot/firmware/$KERNEL.img
  2. 根据你的 内核版本,运行以下命令:

    • 适用于 6.4 及以下版本的内核:

      $ sudo cp arch/arm/boot/dts/*.dtb /boot/firmware/
    • 适用于 6.5 及以上版本的内核:

      $ sudo cp arch/arm/boot/dts/broadcom/*.dtb /boot/firmware/
  3. 最后,复制 overlays 和 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

或者,用不同的文件名复制内核(如 kernel-myconfig.img),而不是覆盖 kernel.img 文件。然后,编辑启动分区中的 config.txt 以选择内核:

kernel=kernel-myconfig.img

将此方法与自定义的`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

构建配置

本节介绍如何在构建内核时应用默认配置。您还可以通过以下方式配置内核:

输入以下命令以创建源文件和设备树文件:

目标架构 目标产品 命令

64-bit

Raspberry Pi 3

$ cd linux
$ KERNEL=kernel8
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2711_defconfig

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

$ cd linux
$ KERNEL=kernel_2712
$ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcm2712_defconfig

32-bit

Raspberry Pi 1

$ cd linux
$ KERNEL=kernel
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcmrpi_defconfig

Raspberry Pi Compute Module 1

Raspberry Pi Zero

Raspberry Pi Zero W

Raspberry Pi 2

$ cd linux
$ KERNEL=kernel7
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2709_defconfig

Raspberry Pi 3

Raspberry Pi Compute Module 3

Raspberry Pi 3+

Raspberry Pi Compute Module 3+

Raspberry Pi Zero 2 W

Raspberry Pi 4

$ cd linux
$ KERNEL=kernel7l
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2711_defconfig

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/bootmnt/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 位内核:

  • 运行以下命令创建当前内核的备份镜像,安装新的内核镜像、overlays、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 位内核:

  1. 运行以下命令创建当前内核的备份镜像,并安装新的内核镜像:

    $ sudo cp mnt/boot/$KERNEL.img mnt/boot/$KERNEL-backup.img
    $ sudo cp arch/arm/boot/zImage mnt/boot/$KERNEL.img
  2. 根据你的 内核版本,运行以下命令安装设备树 blobs:

    • 适用于 6.4 及以下版本的内核:

      $ sudo cp arch/arm/boot/dts/*.dtb mnt/boot/
    • 适用于 6.5 及以上版本的内核:

      $ sudo cp arch/arm/boot/dts/broadcom/*.dtb mnt/boot/
  3. 最后,安装overlays和 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

或者,用不同的文件名复制内核(如 kernel-myconfig.img),而不是覆盖 kernel.img 文件。然后,编辑启动分区中的 config.txt 以选择内核:

kernel=kernel-myconfig.img

将此方法与自定义的 LOCALVERSION 相结合,可将自定义内核与系统管理的原版内核映像分开。有了这种方法,当你的内核无法启动时,你就可以迅速恢复到原版内核。

配置内核

Linux内核是高度可配置的。高级用户可能希望修改默认配置,以根据其需求将其自定义,例如启用新的或实验性的网络协议,或启用对新硬件的支持

配置通常通过 make menuconfig 界面完成。另外,您也可以手动修改 .config 文件,但这可能比较困难。

准备配置

menuconfig 工具需要 ncurses 开发环境头文件才能正常编译。要安装这些头文件,请运行以下命令:

$ sudo apt install libncurses5-dev

接下来,下载内核源代码。尤其要确保已安装 默认本地配置默认交叉编译配置

设置好一切后,就可以编译并运行 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

  • 要上一级或退出,按两次 Esc

  • 要切换二进制选项的状态,按 空格键

  • 选择多选选项的状态,按 Enter 键打开子菜单,按 方向键 浏览子菜单,再按 Enter 键选择状态

  • 要获得选项或菜单的帮助,请按 H

经过编译后,menuconfig 会显示一个子菜单列表,其中包含所有可以配置的选项。选项很多,请慢慢阅读。第一次尝试时,不要轻易启用或禁用大量选项;这样很容易破坏配置,所以要从小处着手,熟悉配置和编译过程。

保存更改

完成更改后,按 Escape 直至提示保存新配置。默认情况下,会保存到 .config 文件中。您可以通过复制该文件来保存和加载配置。

自定义配置后,你就可以 构建内核 了。

给内核打补丁

在构建自定义内核时,您可能希望将补丁或补丁集合(补丁集)应用到 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 config --global user.name "your name"
$ git config --global user.email "your email"

要使用 Git 应用采用 Mailbox 格式的补丁,请运行以下命令:

$ git am -3 /path/to/patches/*

请始终遵循补丁分发者提供的说明。例如,有些补丁集要求针对特定提交打补丁。

内核头文件

要编译内核模块,你需要 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
安装可能需要几分钟。没有进度指示器。

贡献

您可能出于多种原因希望向内核中添加内容:

  • 您编写了一些树莓派专用代码,希望所有人都能从中受益

  • 你为某个设备编写了通用的 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 内核的稳定版本。