linux内核编程--模块开发1
来源:互联网 发布:中国网络作家村 编辑:程序博客网 时间:2024/04/30 03:42
版权说明:引用请注明出处。
虽然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的内核是作为一个整体来运行的,但是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
- linux内核编程--模块开发1
- linux内核编程--模块开发1
- linux-2.6 内核模块编程探索
- linux-2.6 内核模块编程探索
- 深入浅出Linux设备驱动编程--Linux内核模块
- Linux内核模块编程
- Linux内核模块编程
- Linux内核模块编程
- linux内核模块编程
- Linux 内核模块编程
- Linux内核模块编程
- Linux内核模块编程
- Linux内核模块编程
- LINUX内核模块编程
- linux内核模块编程
- linux内核模块编程
- Linux内核模块编程
- Linux 内核模块 编程
- 2007最新骗局 可怕的骗局请告诉周围的人
- 在linux7.1上安装jdk+tomcat+oracle9i 笔记
- 我的2D战棋
- FrmLogin登录窗体
- 公交车上的际遇
- linux内核编程--模块开发1
- Adding a Combo Box to a Field in MAXIMO Release 5
- 汇编指令CPUID
- FormMain主窗体
- HTML元素及控件事件一览表
- Spring Bean工厂创建Bean实例的方法之使用工厂类
- Team Test单元测试总结
- Maximo之緣
- C#基本问题,你会么