Chinaunix首页 | 论坛 | 博客
  • 博客访问: 631860
  • 博文数量: 1008
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 5175
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-31 09:44
文章分类
文章存档

2012年(1008)

我的朋友

分类:

2012-08-01 11:07:20

原文地址:Linux内核模块开发 作者:luozhiyong131

Linux内核的整体结构非常庞大,其包含的组件也非常多,如何使用需要的组件呢:

方法把所有的组件都编译进内核文件,即:zImagebzImage,但这样会导致两个问题:一是生成的内核文件过大;二是如果要添加或删除某个组件,需要重新编译整个内核

 

内核模块具有如下特点:

模块本身并不被编译进内核文件(zImage或者bzImage)

可以根据需求,在内核运行期间动态的安装或卸载

范例(hello world)

#include

#include

 

static int hello_init(void)

{

    printk(KERN_WARNING"hello,world!\n");

    return 0;

}

 

static void hello_exit(void)

{

    printk(KERN_INFO"Goodbye,world!\n");

}

 

module_init(hello_init);

module_exit(hello_exit);

1模块加载函数(必需)

安装模块时被系统自动调用的函数,通过module_init宏来指定,在HelloWorld模块中,模块加载函数为?

2模块卸载函数(必需)

卸载模块时被系统自动调用的函数,通过module_exit宏来指定

 

模块的编译

Linux 2.6下编译模块,一般使用makefile

单文件makefile

ifneq ($(KERNELRELEASE),)

 

obj-m := hello.o

 

else

   

KDIR := /lib/modules/2.6.18-53.el5/build

all:

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

clean:

    rm -f *.ko *.o *.mod.o *.mod.c *.symvers

 

endif

 

多文件makefile

ifneq ($(KERNELRELEASE),)

 

obj-m := mymodule.o

mymodule-objs := file1.o file2.o file3.o

 

else

   

KDIR := /lib/modules/2.6.18-53.el5/build

all:

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

clean:

    rm -f *.ko *.o *.mod.o *.mod.c *.symvers

 

Endif

 

安装与卸载

l         加载insmod (insmod hello.ko)

l         卸载rmmod (rmmod hello)

l         查看lsmod

l         加载modprobe modprobe hello

modprobe 如同insmod, 也是加载一个模块到内核。它的不同之处在于它会根据文件/lib/modules/<$version>/modules.dep来查看要加载的模块, 看它是否还依赖于其他模块,如果是,modprobe 会首先找到这些模块, 把它们先加载到内核。

 

对比应用程序,内核模块具有以下不同:应用程序是从头(main)到尾执行任务,执行结束后从内存中消失。内核模块则是先在内核中注册自己以便服务于将来的某个请求,然后它的初始化函数结束,此时模块仍然存在于内核中,直到卸载函数被调用,模块才从内核中消失

 

模块可选信息

1许可证申明

MODULE_LICENSE用来告知内核, 该模块带有一个许可证,没有这样的说明,加载模块时内核会抱怨。有效的许可证有"GPL“、"GPLv2""GPL and additional rights""DualBSD/GPL""Dual MPL/GPL""Proprietary"

2、作者申明(可选)

MODULE_AUTHOR(Simon Li");

3、模块描述(可选)

MODULE_DESCRIPTION("Hello World Module");

4、模块版本(可选)

MODULE_VERSION("V1.0");

5、模块别名(可选)

MODULE_ALIAS("a simple module");

6、模块参数

通过宏module_param指定模块参数,模块参数用于在加载模块时传递参数给模块。

module_param(name,type,perm)

l         name是模块参数的名称,type是这个参数的类型,

l         perm是模块参数的访问权限

type常见值:

bool:布尔型int:整型charp:字符串型

perm 常见值:

S_IRUGO:任何用户都对/sys/module中出现的该参数具有读权限

S_IWUSR:允许root用户修改/sys/module中出现的该参数

 

实验 内核模块

实验目的:

通过本实验掌握内核模块的编写、编译、加载、卸载;Makefile的编写。

实验要求:

1.编写he|b woHd内核模块

2.编写Make ,编译内核模块

3.安装,卸载该内核模块

实验步骤:

1、根据实验要求编写内核模块hello.cMakefile (见上面代码)

特别强调Makefile KDlR指的是虚拟机所使用的Iinux系统内核源代码所在的路径

2编译内核模块

#make

hello.ko为编译得到的内核模块

3、加载内核模块

#insmod hello.ko

:注意观察输出打印语句

说明:在安装内核模块的时,内核模块初始化函数hello_init得到调用,应该打印输出语句”hello,world!;但并没有在终端上看到相应的信,这是因为printk输出权限不够,在图形化界面中pHnk权限要求KERN~EMERG,而初始化函数中printk语句权限为KERN_WARNING所有打印输出信息都会保存在文件/var/log/message,大家可以通过该文件来查看输出信息。

 

5.查看内核模块

# lsmod

6.卸载内核模块

#rmmod heIlo

实例源码: 内核模块.rar   

/*

 * 模块参数

 * 模块加载时:insmod hello.ko name="LZY" age=20

 */

#include 

#include 

MODULE_LICENSE("GPL");

static char *name = "Lzy";

static int age = 21;

module_param(age, int, S_IRUGO);

module_param(name,charp,S_IRUGO);

 

static int __init hello_init(void)

{

    printk(KERN_EMERG "Name:%s\n",name);

    printk(KERN_EMERG "Age:%d\n",age);

    return 0;

}

static void __exit hello_exit(void)

{

    printk(KERN_EMERG"Module exit!\n");

}

module_init(hello_init);

module_exit(hello_exit);

 

内核符号导出

内核符号的导出使用:

EXPORT_SYMBOL(符号名)

EXPORT_SYMBOL_GPL(符号名)

其中EXPORT_SYMBOL_GPL只能用于包含GPL许可证的模块

实例源码: 内核符号导出.rar   
 

内核打印

中定义了8种记录级别。按照优先级递减的顺序分别是:

KERN_EMERG <0>

用于紧急消息,常常是那些崩溃前的消息。

KERN_ALERT <1>

需要立刻行动的消息。

KERN_CRIT <2>

严重情况。

KERN_ERR <3>

错误情况。

KERN_WARNING <4>

有问题的警告

KERN_NOTICE <5>

正常情况,但是仍然值得注意

KERN_INFO <6>

信息型消息

KERN_DEBUG <7>

用作调试消息

没有指定优先级的printk默认使用DEFAULT_MESSAGE_LOGLEVEL优先级,它是一个在kernel/printk.c中定义的整数。

2.6.29内核中#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */

阅读(144) | 评论(0) | 转发(0) |
0

上一篇:Linux内存管理

下一篇:内核配置与编译

给主人留下些什么吧!~~