最近要写一个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



















