linux内核编程--模块开发1

来源:互联网 发布:中国网络作家村 编辑:程序博客网 时间:2024/04/30 03:42
版权说明:引用请注明出处。
虽然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" );
这个简单的程序以包含了模块的主要特征,每个模块都有一个入口和出口,在这个程序中是hello_init()和hello_exit(),它们分别通过module_init()和module_exit()系统调用注册到内核中,内核在加载这个模块时,调用hello_init()函数,在这个函数中一般做一些初始化工作,如果初始化顺利完成,返回零,否则返回一个非零值。hello_exit()是模块的出口函数,内核在卸载该模块是调用,负责释放资源等。
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
运行make后正常的话会有类似下面的输出:
make -/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'
这时会在生成一个hello.ko的文件。如果你的模块是由多个源文件组成的,那么在Makefile中在加一行就行了:
hello-objs := file_a.o file_b.o


3.加载模块
要加载或
卸载以root用户运行命令insmod或rmmod:
insmod ./hello.ko
使用下面的命令可以看到我们的模块已经加载了:
lsmod | grep hello
使用下面的命令可以卸载该模块:
rmmod hello
这是在用lsmod就看不到hello模块了。但是我们的输入信息到那去了呢,不急,如果你是在X Windows下的XTerm中insmod的,你不会看到输出,使用dmesg就可能看到在加载和卸载模块时的输出内容,只有直接在console下才能直接显示到屏幕上。
我们还可能使用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

呵呵,好,现在我们已经是一个内核模块开发者了,不要停下,继续吧!

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