Fork me on GitHub

【linux】内核-模块(驱动)命令原理

模块的基本描述

  Linux kernel由诸多模块组成,这些模块可以直接与硬件交互,我们也叫它为硬件模块。诸多模块以模块化的方式存在于kernel中。在编译kernel时,可以将需要的模块加入到核心中,也可以将各个子模块编译成各自的单独的模块(模块以ko为扩展名),在需要的时候再分别载入。

 

写一个简单的模块程序

编写模块代码hello.c

#include <linux/init.h>
#include <linux/module.h>

MODULE_AUTHOR("voipman");
MODULE_LICENSE("Dual BSD/GPL");

static int hello_init(void)
{
    printk(KERN_ERR"Module, hello world.\n");
    return 0x0;
}

static void hello_exit(void)
{
    printk(KERN_ERR"Module, hello exit.\n");
    return;
}
module_init(hello_init);
module_exit(hello_exit);

编写Makefile文件

CURR_PATH   = $(shell pwd)
KERNEL_PATH = /usr/src/kernels/3.10.0-1160.el7.x86_64
BUILD_PATH  = $(CURR_PATH)/build
obj-m := hello.o
default:
    make -C $(KERNEL_PATH) M=$(CURR_PATH) modules
.PHONY:clean
clean:
    @$(RM) *.o *.ko *.mod.* Module.*

 

编写Makefile文件时,需要设定内核源码的地址KERNEL_PATH,需要linux系统首先安装kernel-devel包,如下

yum install kernel-devel

安装完毕内核开发包后,检查内核代码的路径/usr/src/kernels/3.10.0-1160.el7.x86_64/

编译demo模块 make,会生成hello.ko的模块文件。

 

到此,模块文件已经准备ok,实验这些模块操的命令。

 

管理模块的各个命令说明

insmod

      加载hello.ko模块,会触发系统调用finit_module,通过系统调用自动调用module_init函数,执行回调函数hello_init,输出对应初始化信息。

[root@localhost ldd]# strace insmod hello.ko
...
stat("/home/w/ldd", {st_mode=S_IFDIR|0775, st_size=235, ...}) = 0
stat("/home/w/ldd/hello.ko", {st_mode=S_IFREG|0644, st_size=101648, ...}) = 0
open("/home/w/ldd/hello.ko", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1", 6)               = 6
lseek(3, 0, SEEK_SET)                   = 0
fstat(3, {st_mode=S_IFREG|0644, st_size=101648, ...}) = 0
mmap(NULL, 101648, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9f4b253000
finit_module(3, "", 0)                  = 0
munmap(0x7f9f4b253000, 101648)          = 0
close(3)                                = 0
exit_group(0)                           = ?

从系统调用发现,insmod加载模块时,会调用系统调用 finit_module 实现模块的初始化,从而执行内核代码的init_module函数。

CentOS加载模块的系统调用号是313

#define __NR_finit_module 313

 

几个主要的内核函数执行顺序如下

finit_module --> load_module --> do_init_module 

在do_init_module中会执行模块初始化函数module_init的函数hello_init,如下

static noinline int do_init_module(struct module *mod)
{
    // ...
    /* Start the module */
    if (mod->init != NULL)
        ret = do_one_initcall(mod->init);

      // ...

 

 

查看模块的执行信息

[root@localhost ldd]# cat /proc/kmsg
<3>[28204.904444] Module, hello world.

 加载模块后,会在系统目录下产生模块的目录

[root@localhost ldd]# ls /sys/module/hello/
coresize     initsize     notes/       rhelversion  srcversion   uevent
holders/     initstate    refcnt       sections/    taint
[root@localhost ldd]# cat /sys/module/hello/initstate
live

 

另外,加载模块,需要加载着明确的指定模块的依赖关系。如 模块A依赖模块B,加载模块A之前需要先加载模块B。

  

insmod modB
insmod modA

 

lsmod

  列出加载的模块,找出上面开发的hello.ko模块信息

[root@localhost ldd]# lsmod |grep hello
hello                  12496  0

 这个12496代码模块的大小,可以从文件中读取

[root@localhost ldd]# cat /sys/module/hello/coresize
12496

 

rmmod

  移除模块时,系统会调用系统调用delete_module,更新系统调用如下

[root@localhost ldd]# strace rmmod hello.ko
....
open("/sys/module/hello/refcnt", O_RDONLY|O_CLOEXEC) = 3
read(3, "0\n", 31)                      = 2
read(3, "", 29)                         = 0
close(3)                                = 0
delete_module("hello", O_NONBLOCK)      = 0
exit_group(0)                           = ?
+++ exited with 0 +++

 

在内核代码中调用module_exit函数,执行回调函数hello_exit,输出对应的退出信息。

 

[root@localhost ldd]# rmmod hello.ko
[root@localhost ldd]# cat /proc/kmsg
<3>[28947.565658] Module, hello exit.

 

删除模块的系统调用号176

#define __NR_delete_module 176

几个主要的内核函数执行顺序如下

delete_module --> free_module 

其中delete_module系统调用函数如下,会调用模块的退出函数mod->exit()

SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
        unsigned int, flags)
{
    struct module *mod;
    
    // ...
    /* Final destruction now no one is using it. */
    if (mod->exit != NULL)
       mod->exit();
    // ...  
    free_module(mod);
    // ... 

}

 

modprobe

  加载模块,检查模块依赖的方式加载模块

   -r  删除模块

  modules.dep

 

depmod

  分析kernel下的模块,将要载入的模块的相互依赖保存到依赖文件(modules.dep)

 

参考材料:

https://github.com/gityf/ldd

 

Done.

posted @ 2021-08-24 18:09  Mr.YF  阅读(835)  评论(0编辑  收藏  举报