一、驱动模块的编译
1. 内核模块的编译机制
Linux 内核通过 Kbuild 系统 管理模块编译,需在内核源码树或外部独立编译。
核心文件:
- Kconfig:配置选项(通过
make menuconfig
选择是否编译为模块)。 - Makefile:定义如何编译驱动代码。
2. 编译流程
场景 1:将驱动集成到内核源码树中
- 将驱动代码放入内核源码目录(如
drivers/char/my_driver/
)。 - 修改
Kconfig
(添加配置选项):# drivers/char/my_driver/Kconfig config MY_DRIVER tristate "My Char Driver Support" default n help This is a sample character device driver.
- 修改
Makefile
(关联编译规则):# drivers/char/my_driver/Makefile obj-$(CONFIG_MY_DRIVER) += my_driver.o
- 配置内核:
make menuconfig # 进入 Device Drivers → Character devices → 启用 MY_DRIVER(设置为 M 或 *)
- 编译模块:
生成的make modules -j$(nproc) # 仅编译模块
.ko
文件位于drivers/char/my_driver/my_driver.ko
。
场景 2:独立编译外部驱动模块(推荐开发阶段)
- 创建驱动源码文件(如
my_driver.c
)。 - 编写
Makefile
:# 外部驱动的 Makefile obj-m := my_driver.o # 编译为模块 KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build # 内核头文件路径 all: make -C $(KERNEL_DIR) M=$(PWD) modules # 调用内核构建系统 clean: make -C $(KERNEL_DIR) M=$(PWD) clean
- 编译模块:
make # 生成 my_driver.ko
二、驱动模块的安装与加载
1. 安装模块到系统
将 .ko
文件复制到内核模块目录:
sudo make modules_install # 若在内核源码树中编译
# 或手动安装外部模块
sudo cp my_driver.ko /lib/modules/$(uname -r)/kernel/drivers/char/
sudo depmod -a # 更新模块依赖关系
2. 加载模块
- 手动加载:
sudo insmod /path/to/my_driver.ko # 直接加载(不处理依赖) # 或 sudo modprobe my_driver # 自动处理依赖(需已安装到模块目录)
- 查看已加载模块:
lsmod | grep my_driver
3. 卸载模块
sudo rmmod my_driver # 卸载模块
# 或
sudo modprobe -r my_driver # 处理依赖卸载
三、关键命令详解
1. make modules
- 作用:仅编译内核配置中标记为 模块(M) 的驱动。
- 使用场景:在内核源码树中修改驱动代码后重新编译。
2. make -C $(KERNEL_DIR) M=$(PWD) modules
- 作用:编译外部独立驱动模块。
- 参数解析:
-C $(KERNEL_DIR)
:切换到内核源码目录执行构建。M=$(PWD)
:指定外部模块源码路径。
3. depmod
- 作用:生成模块依赖关系文件(
modules.dep
),供modprobe
使用。
四、常见问题与解决
1. 模块版本不匹配
- 报错:
version magic 'X.X.X mod_unload' should be 'Y.Y.Y'
- 原因:驱动编译时使用的内核版本与当前系统内核版本不一致。
- 解决:
# 确保使用正确的内核头文件 sudo apt install linux-headers-$(uname -r)
2. 模块签名问题(Secure Boot 启用时)
- 报错:
module verification failed: signature and/or required key missing
- 解决:
- 禁用 Secure Boot(不推荐)。
- 或为模块签名(需配置内核签名密钥)。
3. 依赖未加载
- 报错:
Unknown symbol in module
- 解决:使用
modprobe
替代insmod
,自动加载依赖模块。
五、高效开发技巧
- 快速测试模块:
make && sudo insmod my_driver.ko # 编译后立即加载 dmesg | tail # 查看内核日志
- 调试符号支持:
在Makefile
中添加调试选项:EXTRA_CFLAGS += -g -DDEBUG
- 模块参数传递:
加载时指定参数:// 驱动代码中定义参数 static int my_param = 0; module_param(my_param, int, 0644);
sudo insmod my_driver.ko my_param=42
六、总结
操作 | 命令/步骤 | 说明 |
---|---|---|
编译外部模块 | make -C /lib/modules/$(uname -r)/build M=$(PWD) modules | 依赖内核头文件 |
安装模块到系统 | sudo make modules_install 或 sudo cp *.ko /lib/modules/... | 需更新 depmod |
加载模块 | sudo modprobe <module> | 自动处理依赖关系 |
调试模块 | dmesg + printk | 查看内核日志 |
通过合理使用 make modules
和模块加载工具,可以高效开发和调试 Linux 驱动程序。建议在开发阶段使用外部独立编译,快速迭代测试。
参考: