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

版权说明:引用请注明出处。
虽然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

你可能感兴趣的:(linux内核编程--模块开发1)