Linux模块代码、编译、加载、卸载一条龙

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

可以在终端看到一下输出
加载ko模块的输出
再用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

猜你喜欢

转载自blog.csdn.net/weixin_40313940/article/details/128497982