admin 管理员组

文章数量: 1087139


2024年4月18日发(作者:免费建站对比)

~ 

Di ssection of Linux Kerne1 ModuIe ImpIementation MechaniSill 

张楠 

Zhang Nan 

(华东交通大学,江西南昌330013) 

(East China Jiaotong University,Jiangxi Nanchang 33001 3) 

摘要:本文讨论了操作系统的两种基本组织方式,即一体化内核及微内核的基本概念,分析了它们各 

自的优缺点,进而阐明了在Linux下引入内核模块的主要动机,着重以图解的方式论述了Linux内核模块的 

实现机制。 

关键词:一体化内核;微内核;内核模块;内核符号表 

中图分类号:TP316 文献标识码:A 文章编号:1671.4792.(2ol1)5.0092—04 

Abstract:This paper mainly discussed two operating system organization models:monolithic kernel and mi- 

cro kernel,analyzed their advantages and disadvantages.Then ta ̄ed about the motives of introduction of Linux 

, 

kernel module,finally illustrated the Linux kernel:module implementation mechanism with chart. 

Keywords:Monolithic Kernel;Micro Kernel;Kernel Module;Kernel Symbol Table 

0引言 

而如果把所有的操作系统管理模块都放在特权 

现代操作系统从功能构成上来说主要包括进程 

管理、内存管理、文件管理、设备管理以及网络通信 

模式下运行,则称之为一体化组织,见图二所示。 

等几大模块。为了支持构建安全操作系统,现代 

CPU一般都提供了至少两种运行模式:特权模式与 

用户模式。根据各个管理模块是否放在特权模式下, 

操作系统有微内核和一体化内核两种组织方式。如 

果仅把必需的进程通信管理、中断管理以及内存管 

理放在特权模式下运行,而把设备管理模块、文件系 

统管理模块、网络通信管理模块放在用户模式下运 

行,称之为微内核组织方式,见图一所示。 

囤国圈圉圉 

叫 圈囤圈 

图二一体化内核组织方式 

传统的Unix及大部分类Unix操作系统基本上 

都属于一体化内核组织方式,而Mach、Windows 

NT、Window 2000/XP等基本属于微内核组织方式。 

目目圉圈圈 

圈圈 

图一微内核组织方式 

其中一体化内核组织方式的优点是效率高、安全,缺 

点是不容易扩展,要增加一种新设备驱动或文件系 

统等功能必须对内核重新编译定制,而且占用内存 

较多;而微内核组织方式的优点是可扩展性好,占用 

内存少,缺点是效率低,也没有前者安全。 

1 Linux内核模块引入动机及其实现基本思想 

从上可以看出两种内核组织方式都有各自的 

优缺点,在Linux中引入内核模块机制的主要动机 

正是为了充分吸取两者的优点,克服它们的缺点。 

内核模块本质上是一种目标对象文件,没有链 

接,不能独立运行,但可以动态加载到内核并与内核链 

序代码之外也有一张符号表,记录了此内核模块提 

供的函数服务、符号变量及它们的相对地址,如fl 

的相对地址为l5,同时也记录了它可能要引用到的 

亡= 

3 

c 

× 

正在运行的内核中函数服务。但编译时它并不知道 

这些函数及全局变量的地址,故在图四的符号表中 

的s1、f3的地址用“?”表示。 

起j豳坤~ 

鞠七, o一 

接从而成为内核的一部分。其基本机理是,首先Linux 

内核本身有一张内核符号表,此表中主要包括用来描 

述系统提供哪些函数服务、系统全局变量及它们对应 

模 

一 

块 

实 

现 

机 

制 

m1 

mZ Z奋 

分 

在内核中的位置。凡是需要输出的函数及系统全局变 

量,在Linux源代码文件中都用一个宏EX. 

PORT SYMBOL将其输出,以使内核各个模块能够 

互相引用。例如: 

EXPORT

_

SYMBOL ̄emel_tbread); 

同理,每个内核目标模块也有一张类似的符号 

表,其中定义了此模块所提供的功能函数以及变 

量,以及此模块可能要用到的系统内核中的函数及 

变量,但此时又不知其实际地址。为了使内核模块 

真正成为Linux系统内核的一部分,必须将此内核 

模块动态装入到内存中并把相应的各种符号函数 

解析定位好,之后内核模块提供的各种函数才能真 

正被使用。具体可以用下面的图三至图五来说明其 

实现机理。图三是Linux操作系统初始内核映象,其 

中包括系统代码部分和相应的Linux系统内核全局 

符号表,其中f3的内核位置为52,sl为35,依此类 

推。 

。{

・恭 

号} 

・鱿 

p|I 

●蛮 

图三初始系统内核映象 

类似地,图四是一个内核模块映象,其中除了程 

曩1 -, 

蒸 卜 ,f231 l 4 .,凸o  

析 

棚l:=: 

. 

—IZ-_‘;, 

●1=f_ 块@ 寰@ 

苎2 

结束地~ 

图四内核模块映象 

当要把图四所示的内核模块装入到正在运行的 

像图三所示的Linux操作系统内核中,必须完成图 

三操作系统内核模块与图四内核模块的动态链接。 

具体过程是操作系统内核首先为要链人其中的内核 

模块分配内存,将其程序代码装入其中,根据分配的 

起始地址对内核模块内部的函数及变量地址进行重 

新定位。同时在操作系统内核符号表中加入此内核 

模块中定义的函数符号及变量,以便内核中的其它 

子系统能够获得这个刚链人其中的模块的服务。例 

如内核模块中n原来的相对地址为15,由于在装 

入地址是300,故重定位地址应为3 1 5;还有原来在 

内核模块中不知道f3,这时由于装入内存时知道B 

的内核地址是52,所以也要做相应设置,同时在操 

作系统全局符号表中增加内核模块所定义的功能函 

数及变量符号。整个插入内核模块操作系统内核映 

象如图五所示。 

2模块技术分析 

Linux中超级用户可以通过insmod和rmmod 

命令显式地将模块载人核心或从核心中将它卸载。 

核心也可在需要时,请求守护进程kemeld装载和卸 

载模块。通过动态地将代码载人核心可以减小核心 

~ 

图五插入内核模块之后的系统内核映象 

代码的规模,使核心配置更为灵活。Linux允许模块 

堆栈,即一个模块可请求其它模块为之提供服务,当 

模块装载人系统内核时,系统修改内核中的符号表, 

将新装载模块提供的资源和符号加到内核符号表 

中。通过这种方法,新载入的模块可访问已装载模块 

提供的资源。 

若某个模块空闲,用户便可将它卸载出内核。 

在卸载之前,系统释放分配给该模块的系统资源,如 

核心内存、中断等,同时系统将该模块提供的符号从 

核心符号表中删除。 

Linux提供了一组命令用于模块操作,其中以 

insmod、rmmod、l smod、depmod、kemeld这几个命 

令最为重要,它们的功能如表一所示。 

表一模块操作命令 

靠尊 用运 

I Ill f 列出内f;中已安暮的值 

i“、IHl~I 挎悔 安墨到内 中 

lIIIlJlI、I 内援审卸就I簟 

‘pilllI. I生成城 於窝僻 

K rI ¨ 幢 调磨 

Linux内核中与模块有关的数据结构主要有两 

个: 

module和S ymbol_table。module是用来记录 

模块信息和相互引用的关系;而symbol

_

table这个 

结构用来将模块动态链接进核心,这是一个重要的 

数据结构,主要记录两方面的信息:模块提供的函 

数、变量和引用信息。前者用于核心同模块的通信, 

后者记录本模块引用其它模块的情况。两个结构间 

通过由module指向它对应的symbol_table指针来 

联系。 

2.1模块的装入 

装入模块有两种方法:一是通过insmod命令手 

工将模块载人核心,命令的格式为:insmod 

/<path>/modulename.o;二是内核根据需要载入模 

块,当内核发现需要某个模块时,内核请求守护进程 

kerneld载入该模块(内核版本为2.0的调用方式, 

到了2.1以后的版本,这份工作则交由k mod程序, 

通过产生一个内核线程执行modprobe指令并装入 

模块)。当该进程启动时,建立与内核之间的一个I 

PC通道,内核通过该通道发送消息,请求kemeld完 

成具体的任务。kemeld的主要功能是将模块载入 

核心和将它卸载出核心,但kemeld本身并不执行这 

些任务,它只是调用相应命令来完成(如insmod, 

rmmod),也就是说它只是核心负责调度任务的一个 

代理。Kerneld装入模块的过程如图六所示。 

图六Kemeld守护进程模块装入 

由上面分析可以得知,手工装入模块和守护进 

程的按照需要载入模块,最后均通过insmod来实 

现。insmod的具体实现过程如下:首先将待装入模 

块读人虚存,通过符号表定位该模块中引用的核心 

程序和资源指针,再将符号的地址添人模块中的相 

块的AUTOCLEAN和VISITED标志也保存于此, 

但只有由kenerld装入的模块这两个标记才有意义。 

当模块标记为AUTOCLEAN时

系统可以将它们 

广 

3 

C 

模 × 

块 

实 

现 

应位置。当insmod完成模块对符号表的引用后,通 

过syscreatemodule()系统调用,为新模块分配一 

个module数据结构和足够的核心空间,将新分配的 

module结构置于模块列表(module list)中,并置新 

模块状态为UNINITIALIZED。然后系统会将内核 

分配给module的空间映射到insmod进程的地址空 

自动卸载,而当VISITED被标记时表示该模块正在 

被系统的其它部分使用,该模块是不能被卸载的。 

当kemeld请求系统卸载满足上述两个条件的 

模块时,它会遍历系统中模块列表,寻找候选模块。 

系统仅考察标记为AUTOCLEAN和RUNNING的 

模块,若候选模块的VISITED标记未被置位, 

机 

分 

析 

制 

间,这样insmod进程能够将模块拷贝到分配的空 

间。当模块加入到内核中以后,修改内核的符号表, 

因为若一个模块被其它模块引用,则该模块的数据 

结构中包含一个引用该模块的指针列表,所以需要 

同时修改新模块依赖的所有模块中的相关指针。完 

成上述工作之后,内核调用模块的初始化函数,并进 

行模块的安装。最后,置该模块的状态为RUN. 

NING,至此模块加载成功。 

2.2模块的卸载 

相对于模块装载,卸载模块同样也有两种方法:

第一种是用户使用rmmod命令卸载模块,命令的格 

式为:rmmodmodulename。其实质是通过系统调用 

sys_delete

_

module,将指定的module从系统模块链 

中取出,卸载出核心并释放模块占用的内存空间。 

第二种是kemeld自动卸载,能够由kerneld自动卸 

载的模块必须满足两个条件:(1)kerneld根据需要 

自动载人的模块;(2)它们不再需要。Linux中自 

动卸载的机制为:每隔一定的时间,kerneld调用 

sys_delete

_

module系统调用,将满足上述两个条件 

的模块从系统中卸载,定时器的值在kerneld启动时 

进行设置。 

为了保证引用正确性,Linux规定当某个模块 

被核心的某一部分使用时,该模块是不能被卸载的。 

每一个模块均有一个计数器,计数器的值是内核中 

依赖该模块的模块数目(module count)。一个模块的 

模块数目的值保存在它的映像的第一个字节中,模 

那么将该模块卸载,否则,系统清除该模块的VIS. 

ITED标记位,然后考察系统中的下一个模块。当模 

块被卸载时,系统会调用该模块的cleanup子程序, 

通常该子程序是用于释放系统分配给该模块的核心 

资源。若模块的状态为DELETED,则将它从系统的 

模块列表中脱开,修改该模块所依赖的所有模块的 

引用列表(reference list),将卸载的模块从它们的引 

用列表中脱开,以释放分配给该模块的核心内存。 

3结束语 

Linux内核主要通过设置一张内核符号表,并 

提供一些加载动态链接内核模块的几个基本服务函 

数就可以发挥两种内核的优点,这样像文件系统以 

及设备驱动一般都可以用Linux内核模块来实现。 

参考文献 

[1】李善平.边干边学一Linu)【内核指导[M].杭 

州:浙江大学出版社. 

[2]陈莉君.Linux内核设计与实现[M].北京:机 

械工业出版社. 

【3]陈莉君.深入理解Linux内核(第二版)[M】. 

北京:电力工业出版社. 

作者简介 

张楠(1982一),男,北京市人,汉族,本科,华东 

交通大学在读工程硕士。 

95 


本文标签: 模块 内核 系统 核心 内核模块