初始化硬件设备。
这是驱动程序最基本的功能,初始化通过总线识别设备,访问设备寄存器,按照需求配置设备地端口,设置中断等。
向操作系统提供统一的软件接口。
设备驱动程序向操作系统提供了一类设备通用的软件接口,如硬盘设备向操作系统提供了读写磁盘块、寻址等接口,无论是哪种品牌的硬盘驱动向操作系统提供的接口都是一致的。
提供辅助功能。
现代计算机的处理能力越来越强,操作系统有一类虚拟设备驱动,可以模拟真实设备的操作,如虚拟打印机驱动向操作系统提供了打印机的接口,在系统没有打印机制情况下仍然可以执行打印操作。
运行环境不同。
内核模块运行在内核空间,可以访问系统的几乎所有的软硬件资源;普通应用程序运行在用户空间,可以访问的资源受到限制。这也是内核模块与普通应用程序最主要的区别。由于内核模块可以获得与操作系统内核相同的权限,因此在编程的时候应该格外注意,可能在用户空间看到的一点小错误在内核空间就会导致系统崩溃。
功能定位不同。
普通应用程序为了完成某个特定的目标,功能定位明确;内核模块是为其他的内核模块以及应用程序服务的,通常提供的是通用的功能。
函数调用方式不同。
内核模块只能调用内核提供的函数,访问其他的函数会导致运行异常;普通应用程序可能调用自身以外的函数,只要能正确连接就有运行。
1 2 | static int __init init_func( void ); //初始化函数 static void __exit exit_func( void ); //清除函数 |
static修饰符的作用是函数仅在当前文件有效,外部不可见;
__init关键字告诉编译器,该函数代码在初始化完毕后被忽略;
__exit关键字告诉编译器,该代码仅在卸载模块的时候被调用;
insmod命令加载内核模块的时候不检查内核模块的符号是否已经在内核中定义。
modprobe不仅检查内核模块符号表,而且还会检查模块的依赖关系。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /* 内核模块: ModuleHelloWorld.c */ #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> MODULE_LICENSE( "GPL" ); MODULE_AUTHOR( "Mystety" );
/* init function */ static int __init hello_init( void ) {
printk(KERN_ALERT "(init)Hello,World!\n" );
return 0; } /* exit function */ static void __exit hello_exit( void ) {
printk(KERN_ALERT "(exit)Bye-bye,Mystery!\n" ); } module_init(hello_init); module_exit(hello_exit); |
1 | sudo apt-get install linux- source |
1 2 3 4 5 6 7 8 | ifneq ($(KERNELRELEASE),)
obj-m := ModuleHelloWorld.o else
KERNELDIR := /lib/modules/ $(shell uname -r) /build
PWD := $(shell pwd ) default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif |
1 | lsmod | grep ModuleHelloWorld |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> MODULE_LICENSE( "GPL" ); MODULE_AUTHOR( "Mystety" ); static int initValue = 0; //模块参数 initValue = <int value> static char *initName = NULL; //模块参数 initName = <char*> module_param(initValue, int , S_IRUGO); module_param(initName, charp, S_IRUGO); /* init function */ static int __init hello_init( void ) {
printk(KERN_ALERT "initValue = %d initName = %s \n" ,initValue,initName); //打印参数值
printk(KERN_ALERT "(init)Hello,World!\n" );
return 0; } /* exit function */ static void __exit hello_exit( void ) {
printk(KERN_ALERT "(exit)Bye-bye,Mystery!\n" ); }
module_init(hello_init); module_exit(hello_exit); |