Linux内核模块

来源:互联网 发布:mysql 查询一年内 编辑:程序博客网 时间:2024/06/05 19:13

1、内核模块(2.6及以后版本为例)

1.1、概念

内核模块是Linux内核向外部提供的一个接口,其全称为动态可加载内核模块(Loadable Kernel Module,LKM),简称为模块。

简单说就是linux内核是一个单内核(monolithic kernel),即内核是一个程序,这样内核运行的效率比较高。内核模块是内核这个程序中的一部分。linux内核允许模块在内核运行起来后,再加载进内核。

这样设计的好处是,可以先运行起来具有基本系统功能的内核,然后再根据需要添加需要的模块,则内核就不会很大。内核是一个程序,不可能预先把所有的功能模块都编译进内核。

 

1.2、三个基本组成部分(2.6及以后版本为例)

A、两个函数

初始化函数:模块加载进内核的时候做一些初始化工作

注销函数:模块从内核卸载的时候做一些回收工作

 

B、注册两个函数给内核

把初始化及注销函数注册给内核

(注册的意义:内核不仅仅是先编译好的,而且运行起来了,后编译运行的内核模块的函数要提供给内核回调,从语法的角度看,内核不知道。从运行的角度看这个问题,模块函数加载到内存哪里,内核是不知道的。把模块函数登记到内核指定的位置,内核就可以回调到。)

C、授权声明

linux内核是开源的,可以免费使用,但是使用时候是有协议的,一定要遵循。授权协议有几个版本,到内核官网就可以查询到。

 

1.3、范例

#include <linux/module.h>

#include <linux/kernel.h>

/*初始化函数*/

static int __init demo_init(void)

{

return 0;

}

/*注销函数*/

static void __exit demo_exit(void)

{

}

/*授权声明*/

MODULE_LICENSE("Dual BSD/GPL");

/*注册初始化函数*/

module_init(demo_init);

/*注册注销函数*/

module_exit(demo_exit);

 

2、编译环境

2.1、编译模块必须使用编译出内核的内核源码目录树来编译内核

linux内核是一个整体,模块只是其中一部分,所以模块的编译依赖内核。主要需要使用到的是:

A、编译系统

内核使用一个编译系统编译出来的,模块是其的一部分,所以这样编译系统要一致才不会出现问题。

B、内核函数符号表

内核编译出来后会形成一个函数符号与所在地址的一个对应表,这个就是符号表。模块会使用到内核提供的一些函数或是数据,就是根据这个表格来找到内核提供的这些代码或是数据。

C、头文件支持

C语法有声明的概念,就是说编译在编译的时候可以帮我们检查,模块代码中使用的函数原型或是数据类型对不对。

2.2、范例

1

ifneq ($(KERNELRELEASE),)

2

obj-m := demo.o

3

else

4

KERNELDIR ?= /lib/modules/$(shell uname -r)/build

5

PWD       := $(shell pwd)

6

modules:

7

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules

8

endif

9

clean:

10

rm -rf *.o *.symvers *.order *.ko *.mod.c *.markers

第1行:检查变量KERNELRELEASE(内核源码顶层目录下Makefile中定义)是否存在,不存在则走else项

第2行:定义要编译的模块demo.o表示要编译的模块源码文件是demo.c

第3行:ifneq ($(KERNELRELEASE),)不成功则则else下的执行

第4行:定义一个变量KERNELDIR,指定内核源码目录树,这里的是PC下的内核源码目录树路径

第5行:定义一个变量PWD,指定模块源码所在路径

第6行:定义一个伪目标modules

第7行:伪目标modules下的命令行。

$(MAKE)是Makefile默认变量即指定工具make

-C是make 的参数,表示要切换目录

$(KERNELDIR)是变量引用,即内核源码目录树

M=$(PWD)是传递参数,传递的是$(PWD)指定的模块源码路径

modules是目标名

这句命令行的意思:切换到内核源码目录树下,执行其Makefile中的modules目标,并把模块源码路径传递给内核源码目录下的Makefile

第8行:endif,ifneq ($(KERNELRELEASE),)的结束语法

第9行:定义一个伪目标clean

第10行:伪目标clean的命令行,用来删除编译模块源码产生的过程文件。

 

这个简单范例反应了模块源码编译的大概过程如下:

先从模块源码所在路径下执行make,然后根据模块源码所在路径下的Makefile的定义转到内核源码目录树所在目录,并执行其Makefile,并把模块的路径传递给这个Makefile。内核源码目录下的Makefile会根据传递去的模块源码目录,再切换回来模块源码,得到要编译的模块源文件,再执行编译。

 

3、操作模块

这里假定模块文件名xxx.ko(2.6及以后内核编译出来的模块的文件名称的扩展名都是.ko)

模块名,在2中的Makefile范例中“obj-m := demo.o”,demo就是模块名

3.1、加载模块

在终端下执行

#insmod 模块文件名

3.2、卸载模块

#rmmod 模块名

3.3、查看模块

# lsmod

# cat /proc/modules

3.4、查看模块输出信息

#demsg

#cat /proc/kmsg