Skip to main content

Linux 内核头文件

在 Neardi Pi 3 上编译第三方驱动、外置内核模块时,一般需要安装与当前固件匹配的内核头文件。

这里先介绍比较稳妥的做法:在 x86 Ubuntu PC 的 Linux SDK 中生成头文件安装包,再复制到板子上安装和测试。

下载编译好的头文件

已经编译好的 Neardi Pi 3 内核头文件可以从下面的链接下载:

下载内核头文件,提取码:ldkj

下载和安装前,先在板子上查看当前内核版本和架构:

neardi@RK3576:~$ uname -a

选择的头文件需要同时匹配当前运行的内核版本和架构。Neardi Pi 3 使用 aarch64 架构,对应的 Debian 安装包文件名一般以 _arm64.deb 结尾。

例如,uname -a 显示内核版本为 6.1.118、架构为 aarch64,就选择 6.1.118 的 ARM64 头文件。不能只看架构相同,就安装其他内核版本的头文件。

安装下载的头文件

使用 dpkg 安装下载好的头文件包,文件名根据实际下载的版本替换:

neardi@RK3576:~$ sudo dpkg -i ./linux-headers-xxx_arm64.deb

例如:

neardi@RK3576:~$ sudo dpkg -i \
./linux-headers-6.1.118_6.1.118-3_arm64.deb

查看已经安装的 linux-headers 软件包:

neardi@RK3576:~$ dpkg -l | grep linux-headers
ii linux-headers-6.1.118 6.1.118-3 arm64 Linux kernel headers for 6.1.118 on arm64

linux-headers-6.1.118 就是刚安装的头文件包,一般安装在板子的 /usr/src/ 目录:

neardi@RK3576:~$ ls -ld /usr/src/linux-headers-*

在 SDK 中生成头文件

进入 Linux SDK 根目录,先选择 Neardi Pi 3 对应的配置:

neardi@ubuntu2204-pc:~/rk3576-linux-sdk$ ./build.sh lunch

根据当前 SDK 选择对应的 Neardi Pi 3 配置,然后执行:

neardi@ubuntu2204-pc:~/rk3576-linux-sdk$ ./build.sh linux-headers

脚本会准备内核源码,并把头文件安装包放到:

output/linux-headers/

可以用下面的命令查看生成结果:

neardi@ubuntu2204-pc:~/rk3576-linux-sdk$ find output/linux-headers -maxdepth 1 -name "*.deb" -print

SDK 可能会同时生成 amd64armhfarm64 三种安装包。Neardi Pi 3 是 AArch64 系统,板子上要安装文件名以 _arm64.deb 结尾的包:

实际生成的主要文件如下:

linux-headers-6.1-arm64_amd64.deb
linux-headers-6.1-arm64_arm64.deb
linux-headers-6.1-arm64_armhf.deb
linux-headers-aarch64.tar.gz
linux-headers-amd64.tar.gz
linux-headers-armhf.tar.gz

Neardi Pi 3 使用的是:

linux-headers-6.1-arm64_arm64.deb

其他架构的安装包、.tar.gz 文件以及 linux-kbuild-* 软链接都不用复制到板子。

neardi@ubuntu2204-pc:~/rk3576-linux-sdk$ scp \
output/linux-headers/linux-headers-6.1-arm64_arm64.deb \
neardi@<板子IP>:~/

在 Neardi Pi 3 上安装

先安装基本编译工具,再安装刚生成的头文件包:

neardi@RK3576:~$ sudo apt update
neardi@RK3576:~$ sudo apt install -y build-essential
neardi@RK3576:~$ sudo apt install ./linux-headers-6.1-arm64_arm64.deb

不同版本 SDK 生成的文件名可能不一样,安装时以实际生成的文件为准。

检查安装结果:

neardi@RK3576:~$ dpkg -l | grep linux-headers
neardi@RK3576:~$ ls -ld /usr/src/linux-headers-*

编译一个测试模块

新建 hello.c

#include <linux/init.h>
#include <linux/module.h>

static int __init hello_init(void)
{
pr_info("neardi_headers_test: loaded\n");
return 0;
}

static void __exit hello_exit(void)
{
pr_info("neardi_headers_test: unloaded\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Neardi kernel headers test module");

新建 Makefile

obj-m += hello.o

KDIR ?= /usr/src/linux-headers-6.1-arm64

all:
$(MAKE) -C $(KDIR) M=$(CURDIR) modules

clean:
$(MAKE) -C $(KDIR) M=$(CURDIR) clean

编译并加载模块:

neardi@RK3576:~/headers-test$ make
neardi@RK3576:~/headers-test$ file hello.ko
neardi@RK3576:~/headers-test$ sudo insmod hello.ko
neardi@RK3576:~/headers-test$ dmesg | tail
neardi@RK3576:~/headers-test$ sudo rmmod hello
neardi@RK3576:~/headers-test$ dmesg | tail

正常情况下,内核日志中会看到:

neardi_headers_test: loaded
neardi_headers_test: unloaded

版本不匹配

头文件安装包需要和板子当前固件使用同一套 SDK、内核配置及源码版本。

可以对比正在运行的内核版本和模块信息:

neardi@RK3576:~$ uname -r
neardi@RK3576:~/headers-test$ modinfo hello.ko | grep vermagic

如果 insmod 提示 Invalid module format,通常是头文件或内核配置与当前固件不一致。请使用当前固件对应的 SDK 重新生成头文件并编译模块。

在 PI3 板子上编译源码(备选)

也可以把内核源码复制到 Neardi Pi 3,直接在板子上编译头文件安装包。下面的步骤已使用 Rockchip Linux 6.1 内核源码实测。

板端编译占用的存储空间更多,耗时也比在 SDK 中直接生成安装包长。条件允许时,还是建议优先使用前面的 SDK 编译方式。

安装编译依赖

neardi@RK3576:~$ sudo apt update
neardi@RK3576:~$ sudo apt install -y build-essential libncurses-dev \
bison flex libssl-dev libelf-dev cpio rsync bc fakeroot dpkg-dev

将内核源码复制到板子

从 Linux SDK 中复制匹配的内核源码:

neardi@ubuntu2204-pc:~/rk3576-linux-sdk$ scp -r kernel-6.1 \
neardi@<板子IP>:~/

内核源码需要和板子当前使用的 SDK、固件版本对应。

配置内核

neardi@RK3576:~$ cd kernel-6.1
neardi@RK3576:~/kernel-6.1$ make ARCH=arm64 rockchip_linux_defconfig

如果编译出来的外置模块需要加载到当前固件,内核源码、配置和版本都要与固件保持一致。默认配置可以生成安装包,但对于修��改过内核配置的固件,模块版本信息不一定匹配。

处理 DTC 头文件路径

实测使用的 Rockchip Linux 6.1 源码执行 bindeb-pkg 时,可能会报错:

fatal error: ../../uapi/linux/media-bus-format.h: No such file or directory

创建缺少的目录并复制头文件:

neardi@RK3576:~/kernel-6.1$ mkdir -p \
scripts/dtc/include-prefixes/uapi/linux
neardi@RK3576:~/kernel-6.1$ cp \
include/uapi/linux/media-bus-format.h \
scripts/dtc/include-prefixes/uapi/linux/media-bus-format.h

编译 Debian 安装包

neardi@RK3576:~/kernel-6.1$ make ARCH=arm64 bindeb-pkg -j4

这个命令还会编译内核和设备树,因此需要等待一段时间。如果板子可用内存不多,可以把 -j4 改成 -j2

生成的安装包位于内核源码的上一级目录:

neardi@RK3576:~/kernel-6.1$ ls ../*.deb

本次实测生成了:

linux-headers-6.1.118_6.1.118-3_arm64.deb
linux-image-6.1.118_6.1.118-3_arm64.deb
linux-image-6.1.118-dbg_6.1.118-3_arm64.deb
linux-libc-dev_6.1.118-3_arm64.deb

Neardi Pi 3 板端成功编译内核头文件

安装头文件

如果只是为了编译外置内核模块,只安装 linux-headers 包即可:

neardi@RK3576:~/kernel-6.1$ sudo dpkg -i \
../linux-headers-6.1.118_6.1.118-3_arm64.deb

不要顺手安装 linux-imagelinux-libc-dev,除非确实需要替换系统中的对应软件包。安装这里生成的 linux-libc-dev,可能会把 Ubuntu 自带版本降级。

检查安装结果:

neardi@RK3576:~$ dpkg -l | grep linux-headers
neardi@RK3576:~$ ls -ld /usr/src/linux-headers-*

安装完成后,可以使用前面的测试模块检查头文件能否正常编译模块,并确认模块的 vermagic 是否与当前运行内核一致。