最近要写一个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 -O0
build: kernel_modules
kernel_modules:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
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