您的位置:首页 > 其它

Hello,Module 最简单的内核模块

2011-08-06 09:18 381 查看
第一个最简单的内核模块什么事都不做,仅在内核加载时打印 “ hello,kernel world ” ,在模块卸载时打印 “ goodbye,kernel
world” ,虽然什么事情也做不了,但这已经是一个可以加载如内核的简单模块了。

在新建hello文件夹下建立两个文件:

hello.c  Makefile


hello.c 内容如下:

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

MODULE_LICENSE("Dual BSD/GPL");
static int __init hello_init(void) //模块的入口,当此模块被加载的时候调用
{
printk(KERN_INFO "hello , kernel world\n");
return 0;
}

static void __exit hello_exit(void) //模块的出口,当模块被卸载的时候调用
{
printk(KERN_INFO " goodbye,kernel world\n ");
}

module_init(hello_init);//指定模块入口函数
module_exit(hello_exit);//指定模块出口函数

//一些基本的模块信息,可以通过 "modinfo 模块名" 查看
MODULE_AUTHOR("xxxx");
MODULE_DESCRIPTION("A simple Hello World Module");
MODULE_ALIAS("a simplest module");  

备注:

1. 引入一些思考,__init __exit 的作用是什么?   以下是完整的宏定义:

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

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

另外,数据部分同样包含以下两个宏。

#define __initdata    __attribute__((__section__(".init.data")))

#define __exitdata   __attribute__((__section__(".ext.data")))

以上四个宏将指定了函数或者数据需要被编译器指定的section位置(代码段,数据段,==)。

init.text和.init.data这两个section段将会在模块被加载后释放掉。

.exit.text.和.exit.data这两个section.段将会在模块被卸载后释放掉。 

所以程序编写过程中可以把某些合适的数据和函数指定到这四个seciton,以达到节约内存的目的。

如果有另一个问题,什么是section? ,这将涉及到一些ELF文件格式和编译方面的知识,读者可以google之。

2.printk函数

内核空间不能使用标准函数库,为了获得内核的打印输出,我们可以使用printk函数,该函数由以下几个级别定义:

#define KERN_EMERG    "<0>"    /* system is unusable */
#define KERN_ALERT    "<1>"    /* action must be taken immediately */
#define KERN_CRIT     "<2>"    /* critical conditions */
#define KERN_ERR      "<3>"    /* error conditions */
#define KERN_WARNING  "<4>"    /* warning conditions */
#define KERN_NOTICE   "<5>"    /* normal but significant */
#define KERN_INFO     "<6>"    /* informational */
#define KERN_DEBUG    "<7>"    /* debug-level messages */


使用方法为: printk(级别 "Hello, world!/n");

未指定日志级别的 printk() 采用的默认级别是 DEFAULT_MESSAGE_LOGLEVEL,这个宏在 kernel/printk.c 中被定义为整数 4,即对应KERN_WARNING。

在 /proc/sys/kernel/printk 会显示4个数值(可由 echo 修改),分别表示当前控制台日志级别、未明确指定日志级别的默认消息日志级别、最小(最高)允许设置的控制台日志级别、引导时默认的日志级别。当 printk() 中的消息日志级别小于当前控制台日志级别时,printk 的信息(要有/n符)就会在控制台上显示。但无论当前控制台日志级别是何值,通过 /proc/kmsg (或使用dmesg)总能查看。另外如果配置好并运行了 syslogd 或 klogd,没有在控制台上显示的 printk
的信息也会追加到 /var/log/messages.log 中。

Makefile 内容如下:

obj-m:=hello.o


备注:

如果内核模块由多个文件组成那应该怎么写这个Makefile呢?  答案是 : obj-m:=hello.o good.o  xxx.o ...

在命令行执行
$
make -C /usr/src/linux M=`pwd` modules


无错误的话将会生成hello.ko 模块,运行insmod工具把模块插入内核:
#
insmod hello.ko 

运行 rmmod工具将模块从内核卸载:
#
rmmod hello

输入以下命令在终端中查看内核输出

#
dmesg | tail -10 


如何可以看到以下输出,那恭喜你成功了!!

[
2840.707373] hello,kernel world

[ 3054.477649] goodbye,kernel world


以上内容估计学习过内核开发的都很熟悉,介绍内核开发的书有ldd3 《Linux 设备驱动开发》第三版,此书已被翻译成中文,可在网上搜索下载。本文这里给出此书的下载链接:

http://ishare.iask.sina.com.cn/f/8189282.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息