《Linux设备驱动开发详解》--Linux内核模块

来源:互联网 发布:1688进货淘宝卖怎么样 编辑:程序博客网 时间:2024/05/30 20:08

#1、Linux内核模块介绍

模块本身不被编译入内核映像,从而控制了内核大小

模块一旦被加载,他就和内核中的其他部分完全一样

```python

#include <linux/init.h>

#include <linux/module.h>


static int hello_init(void)

{

printk(KERN_INFO "Hello World enter\n");

return 0;

}

static void hello_exit(void)

{

printk(KERN_INFO "Hello World exit\n");

}


module_init(hello_init);

module_exit(hello_exit);


MODULE_AUTHOR("XScxy ");

MODULE_LICENSE("Dual BS/GPL");

MODULE_DESCRIPTION("A simple Hello World Module");

MODULE_ALIAS("a simplest module");

```

最简单的内核模块包含:加载函数、卸载函数、对Dual BSD/GPL许可权限的声明以及一些描述信息。

modinfo <模块名> 查看模块信息

insmod *.ko 安装模块 rmmod *.ko 卸载模块

lsmod 查看系统已安装的模块,实际是读取并分析“proc/modules”。内核模块的信息也存在于"sys/module/"目录下,加载hello.ko后 内核中就包含"/sys/module/hello"目录。

modprobe 命令比insmod 命令要强大,他在加载某模块的时候会同时加载该模块所依赖的其他模块。

#2、Linux内核模块程序结构

1、模块加载函数

当通过insmod或者modprobe命令加载内核模块时,模块的加载函数会自动被内核执行,完成本模块的相关初始化工作

2、模块卸载函数

当通过rmmod命令卸载模块的时候 模块的卸载函数会自动被内核执行,完成与模块卸载相关的工作

3、模块许可声明

许可证(LICENSE)声明描述内核模块的许可权限,如果不声明LICESE,模块被加载时将收到内核被污染的警告(kernel tainted)。在Linux2.6中可接受的LICENSE包括“GPL” “GPL v2” "Dual BSD/GPL" "GPL and additional rights" "Dual MPL/GPL" "Proprietary" .

4、模块参数(可选)

模块被加载时传递的参数,他本身对应模块内部的全局变量

5、模块导出符号(可选)

内核模块可以导出符号(symbol 对应于函数或者变量) ,这样其他模块可以使用本模块的变量和函数

6、模块作者等信息声明(可选)

#3、模块加载函数

Linux 内核模块加载函数一般以__init 标识声明,典型的模块加载函数的形式

```python

1 static int __init initialization_function(void)

2 {

3 /* 初始化代码*/

4 }

5 module_init(initialization_function);

```

模块加载函数必须以“module_init(函数名)” 的形式被指定。返回值是int型,若成功返回0,失败返回错误编码,在Linux内核中错误编码是负值,在<linux/errno.h> 中定义。返回相应的错误码才能利用perror等方法去查看。

Linux2.6 内核中,可以使用request_module(const char*fmt,...) 加载模块

Linux中,所有标识为__init 的函数,在连接的时候都放在.init.text这个区段内,此外所有的init函数在区段.initcall.init中还保存一份函数指针,在初始化时内核会通过指针调用这些函数,并在初始化完成后释放init区段。

#4、模块卸载函数

Linux 内核模块卸载函数一般以__exit 标识声明,典型的模块卸载函数的形式

模块卸载函数必须以“module_exit(函数名)” 的形式被指定

通常来说卸载函数要完成与模块加载函数相反的功能,如:注册的资源、动态申请的内存、申请了硬件资源(中断、DMA通道、I/O端口和I/O内存)以及打开的硬件等

和__init一样,__exit 也可以使对应函数在运行完成后自动回收内存。实际上,__init __eixt 都是宏

```python

#define __init __attribute__ ((__section__ (".init.text")))

```

```python

#ifdef MODULE

#define __exit __attribute__ ((__section__ (".exit.text")))

#else

#define__exit __attribute_used_attribute__ ((__section__ (".exit.text")))

#endif

```

数据也可以被定义为__initdata __exitdata.

#5、模块参数

我可以用“module_param(参数名,参数类型,参数读写权限)”

也可以在加载模块的时候带入参数(insmod、modprobe)例:insmod *.ko num=5000 book_name='GoodBook'

#6、导出符号

Linux2.6 的“/proc/kallsyms”文件对应着内核符号表,他记录了符号以及符号所在的内存地址。

模块可以使用如下宏导出符号到内核符号表,可以被其他模块使用

EXPORT_SYMBOL(符号名--函数或者变量名);

EXPORT_SYMBOL_GPL (符号名);

#7、模块声明和描述

Linux 内核模块中我可以 描述声明模块的作者、描述、版本、设备表和别名。

```python

MODULE_AUTHOR("XScxy ");

MODULE_DESCRIPTION("A simple Hello World Module");

MODULE_VERSION("2.6.10");

MODULE_DEVICE_TABLE(table_info);

MODULE_ALIAS("a simplest module");

```

#7、模块的编译

```python

KVERS = $(shell uname -r)

# Kernel modules

obj-m += hello.o

/*多个.c文件编译时*/

#obj-m := modulename.o

#modulename-objs := file1.o file2.o

build:kernel_modules

kernel_modules:

make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules

clean:

make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean


```


0 0
原创粉丝点击