Linux内核模块简介

来源:IT165收集  发布日期:2014-03-27 20:15:51

Linux提供了这样一种机制,这种机制被称为模块。模块具有这样的特点:

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

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

一、模块的组成

一个Linux内核模块主要由如下几个部分组成:

(1)模块加载函数

Linux 内核模块加载函数一般以__init标识声明。

内核模块加载函数:

static int __init initialization_function(void)

{

/*初始化代码*/

}

module_init(initialization_function);

模块加载函数必需以“module_init(函数名)”的形式被指定。它返回整型值,若初始化成功应返回0.而在初始化失败时,应该返回错误编码。在Linux内核里错误编码应该是一个负值,在<linux/errno.h>中定义,包含-ENODEV,

-ENOMEM之类的符号值。

(2)模块卸载函数

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

static void __exit cleanup_function(void)

{

/*释放代码*/

}

module_exit(cleanup_function);

模块卸载函数在模块卸载的时候执行,不返回任何值,必须以"module_exit(函数名)"的形式来指定。

(3)模块许可证声明

MODULE_LICENSE("GPL");

(4)模块参数

我们可以用“module_param(参数名, 参数类型, 参数读/写权限)”为模块定义一个参数。例如下列代码定义了一个整型参数和一个字符指针参数:

static char *book_name = "dissectting Linux Device Driver";

static int num = 4000;

module_param(num, int, S_IRUGO);

module_param(book_name, charp, S_IRUGO);

实例:带参数的内核模块

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


MODULE_LICENSE("GPL");

static char *book_name = "dissectting Linux Device Driver";
static int num = 4000;

static int __init book_init(void)
{
    printk(KERN_ALERT " book name: %s\n", book_name);
    printk(KERN_ALERT " book num: %d\n", num);
    return 0;
}

static void __exit book_exit(void)
{
    printk(KERN_ALERT " Book module eixt\n");
}

module_init(book_init);
module_exit(book_exit);
module_param(num, int, S_IRUGO);
module_param(book_name, charp, S_IRUGO);
/*end*/

编译和运行:

模块加载:

insmod book.ko book_name='GoodBook' num=250

Message from syslogd@localhost at Mar 26 19:52:24 ...

kernel: book name: GoodBook

Message from syslogd@localhost at Mar 26 19:52:24 ...

kernel: book num: 250

模块卸载:

rmmod book

Message from syslogd@localhost at Mar 26 19:54:14 ...

kernel: Book module eixt

(5)模块导出符号

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

模块可以使用如下宏导出符号到内核符号表:

EXPORT_SYMBOL(符号名);

EXPORT_SYMBOL_GPL(符号名);

导出的符号可以被其它模块使用,使用前声明一下即可。EXPORT_SYMBOL_GPL()只适用于包含GPL许可权的模块。

实例:内核模块中的符号导出

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

MODULE_LICENSE("GPL");

int add_integar(int a, int b)
{
    return a + b;
}

int sub_integar(int a, int b)
{
    return a - b;
}

EXPORT_SYMBOL(add_integar);
EXPORT_SYMBOL(sub_integar);
/*end*/

insmod symbol.ko

cat /proc/callsyms | grep integar

f7e42038 r __ksymtab_sub_integar[symbol]

f7e42050 r __kstrtab_sub_integar[symbol]

f7e42048 r __kcrctab_sub_integar[symbol]

f7e42040 r __ksymtab_add_integar[symbol]

f7e4205c r __kstrtab_add_integar[symbol]

f7e4204c r __kcrctab_add_integar[symbol]

f7e42000 T add_integar[symbol]

f7e42010 T sub_integar[symbol]

rmmod symbol

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

在linux内核模块中,我们可以用 MODULE_AUTHOR、MODULE_DESCRIPTION、MODULE_VERSION、MODULE_DEVICE_TABLE、MODULE_ALIAS分别声明模块的作者、描述、版本、设备表和别名。

对于USB、PCI等设备驱动,通常会创建一个MODULE_DEVICE_TABLE,表明该驱动模块所支持的设备:

static struct usb_device_id skel_table[] =

{

USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID),

{ }/*结束*/

};

二、模块的编译

一个简单的Makefile:

/*$$*/
ifneq ($(KERNELRELEASE),)

obj-m := hello.o

else

KDIR := /lib/modules/2.6.32-358.el6.i686/build

all:
    make -C $(KDIR) M=$(PWD) modules

clean:
    rm -f *.ko *.o *.mod.o *.mod.c *.ko.unsigned *.order *.symvers
endif
/*$$*/

Tag标签: 内核   模块   简介  
  • 专题推荐

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规