原贴:http://blog.csdn.net/aero_boy/archive/2007/03/23/1539040.aspx
linux内核编程--模块开发1 <script src="http://blog.csdn.net/count.aspx?ID=1539040&Type=Rank" type="text/javascript"></script> 版权说明:引用请注明出处。
虽 然linux的内核是作为一个整体来运行的,但是linux的内核是由模块化组成的,它允许内核在运行的过程中动态地插入或删除程序,这些程序被放在一个 单独的二进制文件中,即所谓的可装载的内核模块中,简称为模块。支持模块的好处是基本内核镜像可以尽可能的小,而让那些不必要可不常用的部分以模块的形式 单独存在,在需要时在装入,用完后就可以删除掉。
1.第一个模块
下面是一个简单的hello world的内核模块,从中我们可能了解基本的内核模块开发方法。
这 个简单的程序以包含了模块的主要特征,每个模块都有一个入口和出口,在这个程序中是hello_init()和hello_exit(),它们分别通过 module_init()和module_exit()系统调用注册到内核中,内核在加载这个模块时,调用hello_init()函数,在这个函数中 一般做一些初始化工作,如果初始化顺利完成,返回零,否则返回一个非零值。hello_exit()是模块的出口函数,内核在卸载该模块是调用,负责释放 资源等。
MODULE_LICENSE用于指定版权,linux一般使用"GPL"。
MODULE_AUTHOR用于指定代码的工作。
2.构建模块
在2.6内核中,使用新的"kbuild"构建系统,使构建模块更加容易了。我们写的模块可以单独放在一个我们自己的目录中,以可能直接放到源代码做中,下面是一个单独使用的Makefile
运行make后正常的话会有类似下面的输出:
这时会在生成一个hello.ko的文件。如果你的模块是由多个源文件组成的,那么在Makefile中在加一行就行了:
3.加载模块
要加载或卸载以root用户运行命令insmod或rmmod:
使用下面的命令可以看到我们的模块已经加载了:
使用下面的命令可以卸载该模块:
这 是在用lsmod就看不到hello模块了。但是我们的输入信息到那去了呢,不急,如果你是在X Windows下的XTerm中insmod的,你不会看到输出,使用dmesg就可能看到在加载和卸载模块时的输出内容,只有直接在console下才 能直接显示到屏幕上。
我们还可能使用modinfo来看看关于模块更多的东西:
呵呵,好,现在我们已经是一个内核模块开发者了,不要停下,继续吧!
4.printk()函数
记住这里用的是 printk而不是 printf,在内核中我们是不能调用C库中的函数的,不过C库上的大部份函数在内核中都有实现。
printk主要是为内核提供日志功能, 记录内核信息或用来给出警告用的,因些在调用printk时,我们可以指定输入信息的级别,下表列出了可用的级别。
---------------------------
级别 说明
---------------------------
| KERN_EMERG 紧急情况
| KERN_ALERT 需要立即被注意的错误
| KERN_CRIT 临界情况
| KERN_ERR 错误
| KERN_WARNING 警告
| KERN_NOTICE 普通的
| KERN_INFO 非正式的消息
| KERN_DEBUG 调试信息
---------------------------
以上级别没有一个绝对的定义应该在什么时候用,只能你自己拿主意了。
参考文献:
<Linux内核设计与实现>第二版
The Linux Kernel Module Programming Guid
linux内核编程--模块开发1 <script src="http://blog.csdn.net/count.aspx?ID=1539040&Type=Rank" type="text/javascript"></script> 版权说明:引用请注明出处。
虽 然linux的内核是作为一个整体来运行的,但是linux的内核是由模块化组成的,它允许内核在运行的过程中动态地插入或删除程序,这些程序被放在一个 单独的二进制文件中,即所谓的可装载的内核模块中,简称为模块。支持模块的好处是基本内核镜像可以尽可能的小,而让那些不必要可不常用的部分以模块的形式 单独存在,在需要时在装入,用完后就可以删除掉。
1.第一个模块
下面是一个简单的hello world的内核模块,从中我们可能了解基本的内核模块开发方法。
#include
<
linux
/
init.h
>
#include < linux / module.h >
#include < linux / kernel.h >
static int __init hello_init( void ){
printk(KERN_ALERT " Hello World ! " );
return 0 ;
}
static void __exit hello_exit( void ){
printk(KERN_ALERT " Goodbye! " );
}
module_init( hello_init);
module_exit( hello_exit);
MODULE_LICENSE( " GPL " );
MODULE_AUTHOR( " MyName " );
#include < linux / module.h >
#include < linux / kernel.h >
static int __init hello_init( void ){
printk(KERN_ALERT " Hello World ! " );
return 0 ;
}
static void __exit hello_exit( void ){
printk(KERN_ALERT " Goodbye! " );
}
module_init( hello_init);
module_exit( hello_exit);
MODULE_LICENSE( " GPL " );
MODULE_AUTHOR( " MyName " );
MODULE_LICENSE用于指定版权,linux一般使用"GPL"。
MODULE_AUTHOR用于指定代码的工作。
2.构建模块
在2.6内核中,使用新的"kbuild"构建系统,使构建模块更加容易了。我们写的模块可以单独放在一个我们自己的目录中,以可能直接放到源代码做中,下面是一个单独使用的Makefile
obj
-
m :
=
hello.o
KERNELDIR ?= / lib / modules / $(shell uname - r) / build
PWD : = $(shell pwd)
all:
$(MAKE) - C $(KERNELDIR) M = $(PWD)
clean:
rm - rf * .o *~ core .depend . * .cmd * .ko * .mod.c .tmp_versions
KERNELDIR ?= / lib / modules / $(shell uname - r) / build
PWD : = $(shell pwd)
all:
$(MAKE) - C $(KERNELDIR) M = $(PWD)
clean:
rm - rf * .o *~ core .depend . * .cmd * .ko * .mod.c .tmp_versions
make
-
C
/
lib
/
modules
/
2.6
.
17
-
10
-
generic
/
build M
=/
opt
/
sources
/
kernel_prg
make[ 1 ]: Entering directory ` / usr / src / linux - headers - 2.6 . 17 - 10 - generic '
LD / opt / sources / kernel_prg / built - in .o
CC [M] / opt / sources / kernel_prg / hello.o
Building modules, stage 2 .
MODPOST
CC / opt / sources / kernel_prg / hello.mod.o
LD [M] / opt / sources / kernel_prg / hello.ko
make[ 1 ]: Leaving directory ` / usr / src / linux - headers - 2.6 . 17 - 10 - generic '
make[ 1 ]: Entering directory ` / usr / src / linux - headers - 2.6 . 17 - 10 - generic '
LD / opt / sources / kernel_prg / built - in .o
CC [M] / opt / sources / kernel_prg / hello.o
Building modules, stage 2 .
MODPOST
CC / opt / sources / kernel_prg / hello.mod.o
LD [M] / opt / sources / kernel_prg / hello.ko
make[ 1 ]: Leaving directory ` / usr / src / linux - headers - 2.6 . 17 - 10 - generic '
hello
-
objs :
=
file_a.o file_b.o
3.加载模块
要加载或卸载以root用户运行命令insmod或rmmod:
insmod .
/
hello.ko
lsmod
|
grep hello
rmmod hello
我们还可能使用modinfo来看看关于模块更多的东西:
$ modinfo hello.ko
filename: hello.ko
license: GPL
author: Shakespeare
vermagic: 2.6 . 17 - 10 - generic SMP mod_unload 586 REGPARM gcc - 4.1
depends:
srcversion: C44F4F7F7B8E8D49F537485
filename: hello.ko
license: GPL
author: Shakespeare
vermagic: 2.6 . 17 - 10 - generic SMP mod_unload 586 REGPARM gcc - 4.1
depends:
srcversion: C44F4F7F7B8E8D49F537485
呵呵,好,现在我们已经是一个内核模块开发者了,不要停下,继续吧!
4.printk()函数
记住这里用的是 printk而不是 printf,在内核中我们是不能调用C库中的函数的,不过C库上的大部份函数在内核中都有实现。
printk主要是为内核提供日志功能, 记录内核信息或用来给出警告用的,因些在调用printk时,我们可以指定输入信息的级别,下表列出了可用的级别。
---------------------------
级别 说明
---------------------------
| KERN_EMERG 紧急情况
| KERN_ALERT 需要立即被注意的错误
| KERN_CRIT 临界情况
| KERN_ERR 错误
| KERN_WARNING 警告
| KERN_NOTICE 普通的
| KERN_INFO 非正式的消息
| KERN_DEBUG 调试信息
---------------------------
以上级别没有一个绝对的定义应该在什么时候用,只能你自己拿主意了。
参考文献:
<Linux内核设计与实现>第二版
The Linux Kernel Module Programming Guid
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1539040