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

编译与加载

  1. 在源码目录执行 make,生成 hello.ko 文件。
  2. 加载模块:sudo insmod hello.ko
  3. 查看内核日志:dmesg | tail -5,应看到最后一条为 Hello, World!
  4. 卸载模块:sudo rmmod hello
  5. 再次查看日志: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权限。