2024年5月11日发(作者:)

Linux设备驱动程序原理及框架-内核模块入门篇

内核模块介绍 应用层加载模块操作过程 内核如何支持可安装模块 内核提供的接口及作用 模块

实例

内核模块内核模块介绍

Linux采用的是整体式的内核结构,这种结构 采用的是整体式的内核结构, 采用的是整体式的

内核结构 的内核一般不能动态的增加新的功能。为此, 的内核一般不能动态的增加新的功能。为此,

Linux提供了一种全新的机制,叫(可安装) 提供了一种全新的机制, 可安装) 提供了一种全新的机制

模块” )。利用这个机制 “模块”(module)。利用这个机制,可以 )。利用这个机制, 根据需要, 根

据需要,在不必对内核重新编译链接的条件 将可安装模块动态的插入运行中的内核, 下,将可安装

模块动态的插入运行中的内核, 成为内核的一个有机组成部分; 成为内核的一个有机组成部分;或

者从内核移 走已经安装的模块。正是这种机制, 走已经安装的模块。正是这种机制,使得内核 的内

存映像保持最小, 的内存映像保持最小,但却具有很大的灵活性 和可扩充性。 和可扩充性。

内核模块内核模块介绍

可安装模块是可以在系统运行时动态地安装和 卸载的内核软件。严格来说, 卸载的内核软件。

严格来说,这种软件的作用 并不限于设备驱动, 并不限于设备驱动,例如有些文件系统就是以 可安

装模块的形式实现的。但是,另一方面, 可安装模块的形式实现的。但是,另一方面, 它主要用来

实现设备驱动程序或者与设备驱动 密切相关的部分(如文件系统等)。 密切相关的部分(如文件系统等)。

课程内容

内核模块介绍 应用层加载模块操作过程 内核如何支持可安装模块 内核提供的接口及作用 模块

实例

内核模块应用层加载模块操作过程

内核引导的过程中,会识别出所有已经安装的硬件设备, 内核引导的过程中,会识别出所有已经

安装的硬件设备,并 且创建好该系统中的硬件设备的列表树: 文件系统。 且创建好该系统中的硬件

设备的列表树:/sys 文件系统。 (udev 服务就是通过读取该文件系统内容来创建必要的设备 文件

的。)。 。)。根据 文件系统, 文件的。)。根据 /sys 文件系统,内核读取 文件( 目

录下, 文件(位于 /lib/modules/2.6.5-1.358/ 目录下,2.6.5-1 为内 核版本号,请替换为你的系统

版本号),找到对应的模块, ),找到对应的模块 核版本号,请替换为你的系统版本号),找到对应的模块,

加载。 加载。我们可以看到 文件中都是类似如下的 行: alias pci:v*d***-*****sv***-

*****sd

***-*****bc*sc*i* 8139too

内核模块应用层加载模块操作过程

中间的若干符号包含了很多信息, 中间的若干符号包含了很多信息,例如该设备的制造商编 设

备编号等。例如: 号、设备编号等。例如: alias pci:v***-*****d***-*****sv000015ADsd***-

*****bc06 sc00i00 表示该设备的设备编号是 0x7190,制造商编号是 ,制造商编号是x8086, , 等等,

即是代表 即是代表vendor, 模块子系统提供商编号 0x15ad 等等,v即是代表 , sv代表

subsystem-vendor,sd代表 subsystem-device。 代表 , 代表 。

内核模块应用层加载模块操作过程

某一行匹配之后, 通过这些信息和 某一行匹配之后,便加载 后面指定的模块名

称。 工具。 后面指定的模块名称。加载模块使用的是 modprobe 工具。 我们可以发现, 我们可

以发现, 文件中给出的模块只是个 名称,并没有模块文件的绝对路径。 名称,并没

有模块文件的绝对路径。那么 modprobe 工具 如何定位模块文件本身呢?它需要另一个有用的文

件: 如何定位模块文件本身呢?它需要另一个有用的文件: 。该文件和

在同一个目录下。 在同一个目录下。 该文件的内容是像下面一样的行文本: 该文件

的内容是像下面一样的行文本: /lib/modules/2.6.16.27/kernel/drivers/net/ :

/lib/modules/2.6.16.27/kernel/drivers/net/

内核模块应用层加载模块操作过程

当内核通过 文件确定需要加载 8139too 模 块时, 块时,调用 modprobe

8139too,modprobe 工具再通过读 , 取 文件找到 行,冒号前的文本

给 出了该模块的绝对路径, 出了该模块的绝对路径,而后面的文本则是在加载该模块前 需要先行加

载的模块,也就是它所依赖的模块。(模块的依 需要先行加载的模块,也就是它所依赖的模块。(模块

的依 。( 赖性后面讲解) 赖性后面讲解) 以上讨论的是内核启动中,发现硬件, 以上讨论的是内核启

动中,发现硬件,并且成功匹配模块 名称并加载的情况。但如果内核没有成功匹配合适的模块呢? 名

称并加载的情况。但如果内核没有成功匹配合适的模块呢? 我们就需要作一些工作自己加载了。 我

们就需要作一些工作自己加载了。 当然, 加载某个模块, 当然,我们可以每次手动调用 insmod 加

载某个模块,但 如果是硬件设备驱动的话, 如果是硬件设备驱动的话,我们自然更愿意让它在系统

引导 时便加载。 时便加载。

课程内容

内核模块介绍 应用层加载模块操作过程 内核如何支持可安装模块 内核提供的接口及作用 模块

实例

内核模块内核如何支持可安装模块

每个已安装模块在内核中都有一个module数据结构 数据结构 每个已安装模块在内核中都有一

个 通过系统调用create_module()创建) 创建) (通过系统调用 创建

内核模块内核如何支持可安装模块

/* Sysfs stuff. */ struct module_kobject mkobj; struct module_param_attrs *param_attrs;

struct module_attribute *modinfo_attrs; const char *version; const char *srcversion; struct

kobject *drivers_dir; /* Exported symbols */ const struct kernel_symbol *syms; unsigned int

num_syms; const unsigned long *crcs;

内核模块内核如何支持可安装模块 …

/* Startup function. */ int (*init)(void); … #ifdef CONFIG_MODULE_UNLOAD /* Reference

counts */ struct module_ref ref[NR_CPUS]; /* What modules depend on me? */ struct list_head

modules_which_use_me; /* Who is waiting for us to be unloaded */ struct task_struct *waiter;

/* Destruction function. */ void (*exit)(void); #endif … };

内核模块内核如何支持可安装模块

struct kernel_symbol { unsigned long value; const char *name; }; struct module_ref

{ local_t count; } ____cacheline_aligned;

内核模块内核如何支持可安装模块

在内核的源代码module.c中的静态全局变量 中的静态全局变量modules, 在内核的源代码 中

的静态全局变量 , 所有安装的模块会链入到这个链表上, 开始, 所有安装的模块会链入到这个链

表上,从modules开始, 开始 所有已安装模块的module结构链接在一起成为一条链。 结构链接

在一起成为一条链。 所有已安装模块的 结构链接在一起成为一条链

modules next prev

module 1 … next prev …

module 2 … next prev …

课程内容

内核模块介绍 应用层加载模块操作过程 内核如何支持可安装模块 内核提供的接口及作用 模块

实例

核模块应用层接口介绍

内核提供了哪些接口来支持模块呢? 内核提供了哪些接口来支持模块呢? create_module 在

内核中创建一个 在内核中创建一个module实例,以 实例, 实例 便内核能对其进行管理

init_module 对刚创建的 对刚创建的module进行初始化 进行初始化 query_module 查询有关

查询有关module的各种信息,比如模 的各种信息, 的各种信息 依赖模块、被依赖模块、 块、依

赖模块、被依赖模块、模块导出的符号等等 delete_module 从内核中删除符号