1. 编写第一个内核模块

编写第一个内核模块:Hello World 学习卡片

任务目标

编写一个Linux内核模块,在加载时打印Hello, Kernel!,卸载时打印Goodbye, Kernel!,并掌握内核模块的基本框架、Makefile编写及编译加载流程。

环境依赖

  • Linux系统(本案例以Ubuntu 22.04为例)
  • 已安装的内核头文件:sudo apt install linux-headers-$(uname -r)
  • 构建工具:sudo apt install build-essential
  • 需要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, Kernel!\n");
    return 0;
}

static void __exit hello_exit(void)
{
    printk(KERN_INFO "Goodbye, Kernel!\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
KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all:
	$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
	$(MAKE) -C $(KDIR) M=$(PWD) clean

编译与加载

  1. 在源码目录执行make,生成hello.ko文件。
  2. 加载模块:sudo insmod hello.ko
  3. 查看加载日志:dmesg | tail -5,应看到Hello, Kernel!。
  4. 卸载模块:sudo rmmod hello
  5. 再次查看日志:dmesg | tail -5,应看到Goodbye, Kernel!。
  6. 清理编译产物:make clean

验证判定标准

  • make无报错且生成hello.ko文件。
  • insmod后dmesg输出包含Hello, Kernel!。
  • rmmod后dmesg输出包含Goodbye, Kernel!。
  • lsmod | grep hello在加载期间能列出模块,卸载后无输出。

常见问题

  • 权限错误:insmod/rmmod需root权限,使用sudo。
  • 头文件缺失:编译报错找不到linux/module.h时,安装对应内核头文件。
  • 日志不显示:若dmesg无输出,检查printk级别是否被控制台过滤,可尝试dmesg -n 8后重试。
  • 模块已存在:重复加载报File exists,先rmmod或重启。

本案例演示了内核模块的最小完整框架:module_init和module_exit宏注册入口/出口函数,printk输出日志,Makefile通过内核构建系统完成编译。掌握此流程后,后续案例将在此基础上扩展设备操作、文件接口等复杂功能。