Jetson 内核模块编译与板端验证记录
记录日期:2026-10-05(依据本次对话中的终端输出整理;实际执行的钟表时间未记录)
实验对象:最小内核模块
led.c→led.ko;代码通过日志演示模块加载和卸载,尚未控制实体 LED 。相关课程笔记:内核模块的测试:从三要素到验证。
证据边界:下文列出的版本、命令和输出来自本次实际记录。模块从虚拟机传到开发板的具体命令、IP 和交叉编译器完整路径没有出现在终端记录中,不作为已验证事实。
1. 本次实验完成了什么
在 x86_64 Ubuntu 虚拟机中,先识别出当前 Ubuntu 与 Jetson 使用的不同内核 ,再用 Jetson 的内核构建目录交叉编译出 AArch64 led.ko。模块传到 Jetson 后,板端 insmod、lsmod、dmesg、rmmod 的输出证明加载入口和卸载入口都执行成功。
text
Ubuntu 虚拟机:x86_64 / 5.15.0-139-generic
│ 交叉编译:Jetson 4.9.253-tegra 构建目录 + ARCH=arm64
▼
led.ko:AArch64 / vermagic 4.9.253-tegra
│ 文件已到达 Jetson 的 /home/aidb
▼
Jetson:aarch64 / 4.9.253-tegra → 加载 → 查日志 → 卸载
2. 先分清虚拟机与开发板
| 环境 | 终端提示符 | uname -r |
uname -m |
用途 |
|---|---|---|---|---|
| Ubuntu 虚拟机 | yhai@yhai:~/sharef/LED$ |
5.15.0-139-generic |
x86_64 |
编辑和交叉编译模块。 |
| Jetson 开发板 | aidb@ubuntu:~$、aidb@linux:~$ |
4.9.253-tegra |
aarch64 |
加载并运行最终模块。 |
开发板的 /proc/version 还显示:4.9.253-tegra、SMP PREEMPT,内核由 Linaro GCC 7.3.1 编译。在虚拟机里运行 uname 只能得到虚拟机的信息;要确认目标内核,必须在开发板终端运行。
3. 选择匹配的内核构建目录
老师 Makefile 中的 KERNELDIR ?= ~/linux 是老师自己的路径。最开始在虚拟机中用 /lib/modules/$(uname -r)/build 得到:
text
/usr/src/linux-headers-5.15.0-139-generic
这可以编译给 Ubuntu 虚拟机加载 的模块,但生成文件显示 ELF ... x86-64,modinfo -F vermagic led.ko 是 5.15.0-139-generic SMP mod_unload modversions,所以不能把它当作 Jetson 模块。
进一步查到两个 4.9.253-tegra 候选目录:
| 候选目录 | 已核对的情况 | 本次决定 |
|---|---|---|
/home/yhai/bsp/Linux_for_Tegra/rootfs/usr/src/linux-headers-4.9.253-tegra-ubuntu18.04_aarch64/kernel-4.9 |
有 Makefile、.config、Module.symvers、include/generated/autoconf.h;其中 scripts/mod/modpost 是 ARM aarch64 程序。 |
本次编译主机是 x86_64,不选这个目录。 |
/home/yhai/bsp/Linux_for_Tegra/source/public/kernel/kernel-4.9 |
同样有上述构建文件;kernel.release 为 4.9.253-tegra;其中 scripts/mod/modpost 是 x86-64 程序。 |
本次选为 KERNELDIR。 |
在 ~/sharef/LED/Makefile 中,将老师示例路径换为:
make
KERNELDIR := /home/yhai/bsp/Linux_for_Tegra/source/public/kernel/kernel-4.9
KERNELDIR 指目标内核的构建目录 ,不是 led.c 所在目录,也不是虚拟机当前运行内核的头文件目录。这里的 Module.symvers、.config 等文件已存在;仅找到一个叫 kernel-4.9 的文件夹,并不足以证明它可用于外部模块编译。
4. 虚拟机中的编译记录
最初在 ~/sharef 执行 make,报"没有指明目标并且找不到 makefile";进入包含 Makefile 与 led.c 的 ~/sharef/LED 后,才开始模块编译。
切换目标架构前,先清理此前编给 x86-64 的产物,然后在虚拟机执行:
bash
cd ~/sharef/LED
make clean
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu-
file led.ko
modinfo -F vermagic led.ko
关键构建输出:
text
make -C /home/yhai/bsp/Linux_for_Tegra/source/public/kernel/kernel-4.9 M=/mnt/hgfs/ShareFolder/LED modules
CC [M] /mnt/hgfs/ShareFolder/LED/led.o
MODPOST 1 modules
LD [M] /mnt/hgfs/ShareFolder/LED/led.ko
产物检查结果:
text
file led.ko
→ ELF 64-bit LSB relocatable, ARM aarch64
modinfo -F vermagic led.ko
→ 4.9.253-tegra SMP preempt mod_unload modversions aarch64
编译时出现"led.o 的修改时间在未来 0.11 秒后"和"检测到时钟错误"提示,发生在 VMware 共享目录 /mnt/hgfs/ShareFolder/LED。本次 make 仍生成了 AArch64 模块,随后也在板端成功加载;若以后出现增量编译结果异常,可把源码放到 Ubuntu 本地文件系统重新清理、编译。本次未记录交叉编译器的完整路径及 --version 输出。
5. 文件传到板上与启动方式
板端命令在 /home/aidb 成功使用 ./led.ko,说明该文件当时已在这个目录。实际传输命令未保留在本次记录中;后续复现实验时,若板上 SSH 服务和网络可用,可从虚拟机使用:
bash
scp ~/sharef/LED/led.ko aidb@<板子IP>:/home/aidb/
老师在 U-Boot 中配置的是 NFS 启动/根文件系统 ,便于板子访问主机文件。本次验证只需要让 Linux 板端读到 .ko,不需要为了加载模块而改 U-Boot 的 bootargs、bootcmd。insmod、lsmod、rmmod 都是在板子启动后的 Linux shell 中执行的。若已经有可用 NFS,共享它传文件也可以;本次记录不把 NFS 启动视为已执行步骤。
6. Jetson 板端验证记录
在Jetson 开发板 的 aidb@linux:~$ 提示符下:
bash
cd /home/aidb
sudo insmod ./led.ko
lsmod | grep '^led '
sudo dmesg | tail -n 20
sudo rmmod led
sudo dmesg | tail -n 20
实际 lsmod 输出:
text
led 1454 0
这说明模块名 led 当时在已加载列表中。1454 是内核报告的模块大小,最后的 0 是使用计数;0 不代表初始化函数没有运行。
与本模块有关的实际内核日志如下;方括号内是开机后的秒数,不是钟表时间:
text
[ 435.371220] led: loading out-of-tree module taints kernel.
[ 435.376911] led init yhai 1
[ 440.212315] led exit
[ 571.554719] led init yhai 1
[ 571.789900] led exit
435---440 秒是先前的一轮加载与卸载;本次展示的第二轮在 571 秒加载,随后卸载。insmod 和 rmmod 均未报错;入口日志与退出日志分别出现。out-of-tree module taints kernel 是内核记录外部模块的提示,本次并非加载失败。
7. 结果、限制与复现要点
| 验收项 | 结果与证据 |
|---|---|
| 目标架构正确 | file led.ko 显示 ARM aarch64,与板端 uname -m 一致。 |
| 目标内核版本正确 | vermagic 以 4.9.253-tegra 开头,与板端 uname -r 一致。 |
| 模块加载 | insmod 无报错;lsmod 有 led;dmesg 有 led init yhai 1。 |
| 模块卸载 | rmmod 无报错;dmesg 新增 led exit。卸载后的 lsmod 空结果未单独留存。 |
| LED 硬件控制 | 未验证。当前示例只打印生命周期日志,不含已确认的 GPIO 控制证据。 |
以后修改 led.c 再试,应先卸载板上的旧模块,在虚拟机清理并重新交叉编译,核对新 .ko 的架构和 vermagic,再覆盖板端文件并重新加载。这样可避免把旧产物或给虚拟机编的 x86-64 模块误当成板端新版本。