在 Ubuntu 上重新编译内核模块
在 Ubuntu 系统上,有时我们需要对某些内核模块进行定制化修改,例如调试 KVM、启用某些未公开的调试路径、加入额外日志等。完整重新编译内核会非常耗时,但好消息是:Linux 的内核构建系统允许我们仅重新编译目标模块,而不需要构建整个内核。
本文介绍如何在 Ubuntu 上为当前正在运行的内核版本重新编译一个模块,并正确安装和加载它。示例模块为 kvm-intel.ko。
准备内核源码
Ubuntu 提供了与当前内核版本在同一 ABI 下的源码,可以通过 apt-get 直接获取:1
apt-get source linux-image-unsigned-$(uname -r)
执行后目录中通常会出现类似:1
linux-hwe-6.8-6.8.0/
这就是 Ubuntu 为 HWE 6.8 系列内核提供的完整源码树。
同步配置与符号信息
Kernel module 的编译依赖两个关键文件:
.config— 当前内核的编译配置Module.symvers— 内核导出的符号版本信息
这两者必须与正在运行的内核一致,否则编译出的模块会因为 ABI 不一致而无法加载。
我们将系统中的配置和符号文件复制到源码树中:1
2cp /boot/config-$(uname -r) .config
cp /usr/src/linux-headers-$(uname -r)/Module.symvers .
准备构建环境
执行:1
2make oldconfig && make prepare
make modules_prepare
当它们准备完成后,就可以只编译目标模块了。
只编译目标模块
Linux 内核允许使用 M=<path> 的方式仅构建某个目录下的模块,这大大缩短编译时间。
以 KVM 模块为例:1
make -j$(nproc) M=arch/x86/kvm modules
只会编译:
arch/x86/kvm/kvm.koarch/x86/kvm/kvm-intel.ko(Intel 虚拟化支持)arch/x86/kvm/kvm-amd.ko(如果是 AMD)
以 kvm-intel.ko 为例,编译完成后可以查看模块信息:1
modinfo arch/x86/kvm/kvm-intel.ko
可以确认版本号、依赖项、符号是否正确。
替换内核模块
为了让系统使用我们自己编译的版本,需要将它复制到系统模块目录中:1
2sudo cp arch/x86/kvm/kvm-intel.ko \
/lib/modules/$(uname -r)/kernel/arch/x86/kvm/
然后更新模块依赖:1
sudo depmod -a
这样系统就能识别新的模块文件。
加载模块
卸载旧模块后再加载新的模块。若旧模块已加载,可先移除:1
sudo modprobe -r kvm_intel
然后加载我们编译过的模块,并附带参数:1
sudo modprobe kvm_intel pt_mode=1
若加载成功,说明自定义模块已生效。