最近要写一个Linux的内核模块,记录一下内核模块的代码编写、编译、加载和卸载的基本流程,以作备忘,也希望能帮到有需要的同学。
模块代码
//代码来自https://yangkuncn.cn/kernel_INIT_WORK.html
//init_works.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/workqueue.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/delay.h>struct my_struct_t {char* name;struct work_struct my_work;
};static struct my_struct_t my_name;
static struct workqueue_struct* my_wq = NULL;
static int count;void my_func(struct work_struct *work)
{struct my_struct_t* my_name = container_of(work, struct my_struct_t, my_work);printk(KERN_INFO "Hello kernel, my name is %s", my_name->name);for (count = 1; count < 20; count ++){printk(KERN_INFO"count = %d\n", count);usleep_range(1000000, 1000000);}
}static int __init example_init(void)
{int ret;printk(KERN_INFO"init kernel module\n");my_wq = create_workqueue("my wq");if (!my_wq){printk(KERN_ERR "no memory for workqueue.\n");return 1;}printk(KERN_INFO "create workqueue succussfully.\n");my_name.name = "tom";INIT_WORK(&(my_name.my_work), my_func);ret = queue_work(my_wq, &(my_name.my_work));printk(KERN_INFO"queue work ret = :%d", ret);return 0;
}static void __exit example_exit(void)
{printk(KERN_INFO "Begin exiting work now...\n");flush_workqueue(my_wq);if (my_wq){destroy_workqueue(my_wq);}printk(KERN_INFO "Exit work ok.\n");
}module_init(example_init);
module_exit(example_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("DEBUG");
代码大体功能就是创建一个工作队列,在这个队列上每隔1秒打印一次count数字。
编译
Makefile 此处仅是单源文件的Makefile
多源文件Makefile编写
KVERS = $(shell uname -r)# 要生成的模块名,这里会生成init_works.ko
MODULE_NAME := init_works# 源文件目录
SRC_PATH := init_works/# 作为一个ko模块进行编译
CONFIG_RUNYEE_CAMVIB=m# Kernel modules
obj-$(CONFIG_RUNYEE_CAMVIB) := $(SRC_PATH)$(MODULE_NAME).o# 指定模块的一些编译选项
EXTRA_CFLAGS=-g -O0build: kernel_modules
kernel_modules:make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modulesclean:make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
Makefile和源代码相对路径
执行make命令
执行完make之后,得到一堆东西,其中init_works.ko就是我们需要的内核模块文件。
加载模块
执行命令insmod
insmod init_works/init_works.ko
然后在终端再执行
dmesg --follow
可以在终端看到一下输出
再用lsmod命令查看系统已经加载的模块
可以看到我们的模块已经成功加载到系统上了。
卸载
模块不需要的时候,我们可以卸载它
使用命令
rmmod init_works
从终端的输出可以看到,模块已经被卸载了。
再执行lsmod命令就会发现init_works模块没了,卸载成功!!!
参考
https://yangkuncn.cn/kernel_INIT_WORK.html
https://www.cnblogs.com/mrlayfolk/p/16119159.html
https://www.cnblogs.com/jjzd/p/6438641.html