1. 编写第一个内核模块
任务目标
编写一个最小化的Linux内核模块,实现模块加载时打印"Hello, World!",卸载时打印"Goodbye, World!",并完成编译、加载、验证与卸载的完整闭环。
环境与依赖
- Linux系统(本案例以Ubuntu/Debian为例),内核头文件包
linux-headers-$(uname -r) - 构建工具:
make、gcc - root权限(用于加载/卸载模块)
关键完整代码
创建文件 hello.c:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int __init hello_init(void)
{
printk(KERN_INFO "Hello, World!\n");
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "Goodbye, World!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple Hello World kernel module");
创建同目录下的 Makefile:
obj-m := hello.o
KERNELDIR := /lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(PWD) clean
编译与加载
- 在源码目录执行
make,生成hello.ko文件。 - 加载模块:
sudo insmod hello.ko - 查看内核日志:
dmesg | tail -5,应看到最后一条为Hello, World! - 卸载模块:
sudo rmmod hello - 再次查看日志:
dmesg | tail -5,应看到最后一条为Goodbye, World!
验证方法与判定标准
- 编译通过:
make无报错,生成hello.ko文件。 - 加载成功:
insmod无输出且无报错;lsmod | grep hello能看到模块。 - 功能正确:
dmesg输出中包含Hello, World!(加载后)和Goodbye, World!(卸载后),且无错误堆栈。 - 清理:
sudo rmmod hello后lsmod | grep hello无输出,最后执行make clean清理编译产物。
常见问题
- 报错 "Cannot use CONFIG_MODULE_SIG":若内核开启模块签名强制校验,需在BIOS中关闭Secure Boot,或使用
mokutil --disable-validation后重启。 - dmesg 无输出:确认使用
sudo dmesg查看;部分系统日志级别过滤,可尝试sudo dmesg -c清空后重新加载模块再查看。 - insmod 报错 "Operation not permitted":确认当前内核版本与头文件版本一致,且使用root权限。