现在的位置: 首页 > 综合 > 正文

内核模块

2016年11月28日 ⁄ 综合 ⁄ 共 2482字 ⁄ 字号 评论关闭

内核模块----

linux内核的整体结构庞大,其中包含的组件也很多,如何使用需要的组件?

1--把所有的组件都编译进内核文件,即zImage,bzImage,但这样会导致两个问题:一是生产的内核文件过大,二是,如果要添加或删除某个组件要重新编译整个内核。

内核模块机制---提供一种机制能让内核文件(zImage,bzImage)本身并不包含某组件,而是在该组件需要被使用的时候,动态的添加到正在运行的内核中。

内核模块特点--

模块本身并不被编译进内核文件,可在内核运行期间动态的安装或卸载。

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

MODULE_LICENSE("GPL");
MODULE_AUTHOR("DAVID");
MODULE_DESCRIPTION("Hello world module");

static int __init hello_init(void)
{
    printk(KERN_ERR "hello world!\n");
    return 0;
}
static void __exit hello_exit(void)
{
    printk(KERN_EMERG "hello exit!\n");
}

module_init(hello_init);
module_exit(hello_exit);

程序结构---

1--模块加载函数

安装模块时被系统自动调用的函数,通过module_init宏来指定。

2--模块卸载函数

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

模块的编译---

在linux2.6编译内核模块,通常使用makefile

1--内核模块由一个源文件构成,编写makefile

ifneq ($(KERNELRELEASE),)若变量和空不相等,第一次执行时变量等于空故执行else

obj-m :=hello.o编译出来的内核模块的名字。若想不一样,需要修改。

else
KDIR:= /lib/modules/2.6.18-53.el5/build编译内核模块需要依赖内核源代码,需要给出其路径

all:
    make -C $(KDIR) M=$(PWD) modules   -C表示进入内核源代码目录,$(PWD)表示,模块在当前目录下,总体来说,是使用目录下的内核源代码来编译当前目录下的模块,当第二次编译使用makefile时,KERNELRELEASE就有值了,是内核版本号。

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

endif

2--内核模块由多个源文件构成,编写makefile

ifneq ($(KERNELRELEASE),)

obj-m := hello.o

hello-objs :=main.o add.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

加载---insmod

卸载---rmmod

查看---lsmod

加载----modprobe

modprobe会根据文件/lib/modules/<$version>/modules.dep

来查看要加载的模块,看它是否还依赖于其它模块,若是,会先加载它们到内核。

模块可选信息---

1--许可证申明

宏MODULE_LICENSE用来告知内核,该模块带有一个许可证(GPL,GPLv2等)。

2---MODULE_AUTHER()作者

3--MODULE_DESCRIPTION()描述

4--MODULE_VERSION()版本

5--MODULE_ALIAS()别名

6--模块参数

module_param(name,type,perm)

name-参数名字

type-参数类型

perm--模块参数的访问权限。常见值:

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

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

如:int a=3; char *st;

module_param(a,int,S_IRUGO);

module_param(st,charp,S_IRUGO);

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

内核符号导出--

/proc/kallsyms记录了内核中所有导出符号的名字和地址。

EXPORT_SYMBOL(sum);当在一个模块中使用另外一个模块中的符号,比如函数,需要在被调用函数里导出函数名,调用函数才能使用。

EXPORT_SYMBOL(符号名)

EXPORT_SYMBOL_GPL(符号名)只能用于包含GPL许可证的模块。

内核打印---

在<linux/kernel.h>中定义了8种记录级别。按照优先级递减的顺序分别是:

KERN_EMERG            0

KERN_ALERT              1

KERN_CRIT                2

KERN_ERR                    3

KERN_EMERG            4

KERN_WARNING        5

KERN_NOTICE          6

KERN_INFO            7

KERN_DEBUG          8

没有指定优先级的printk默认使用

DEFAULT_MESSAGE_LOGLEVEL它是一个在kernel/printk.c中定义的整数。

在2.6.29内核中

#define   DEFAULT_MESSAGE_LOGLEVEL 5

控制台优先级配置---纯字符界面

/proc/sys/kernel/printk

6 4 1 7

Console_loglevel

Default_message_loglevel

Minimum_console_level

Default_console_loglevel




【上篇】
【下篇】

抱歉!评论已关闭.