首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

编写内核模块

编写内核模块

内核模块是Linux内核向外部提供的一个插口,其全称为动态可加载内核模块(Loadable Kernel Module,LKM),我们简称为模块。Linux内核之所以提供模块机制,是因为它本身是一个单内核(monolithic kernel)。单内核的最大优点是效率高,因为所有的内容都集成在一起,但其缺点是可扩展性和可维护性相对较差,模块机制就是为了弥补这一缺陷。很多驱动程序都以模块的形式存在,用户可以有选择的加载需要的驱动程序。

一、 什么是模块
  模块是具有独立功能的程序,它可以被单独编译,但不能独立运行。它在运行时被链接到内核作为内核的一部分在内核空间运行,这与运行在用户空间的进程是不同的。模块通常由一组函数和数据结构组成,用来实现一种文件系统、一个驱动程序或其他内核上层的功能。

二、 编写一个简单的模块
  模块和内核都在内核空间运行,模块编程在一定意义上说就是内核编程。因为内核版本的每次变化,其中的某些函数名也会相应地发生变化,因此模块编程与内核版本密切相关。以下例子针对2.6内核:
  tasklet.c文件
[url=][/url]
1 #include <linux/module.h> 2 #include <linux/init.h> 3 #include <linux/kernel.h> 4 #include <linux/interrupt.h>   5 6 static struct tasklet_struct my_tasklet;   7 8 static void tasklet_handler (unsigned long data) 9 {10         printk(KERN_ALERT "tasklet_handler is running.\n");11 }  12 13 static int __init test_init(void)14 {15         tasklet_init(&my_tasklet, tasklet_handler, 0);16         tasklet_schedule(&my_tasklet);17         return 0;18 }  19 20 static void __exit test_exit(void)21 {22         tasklet_kill(&my_tasklet);23         printk(KERN_ALERT "test_exit running.\n");24 }25 MODULE_LICENSE("GPL");  26 27 module_init(test_init);28 module_exit(test_exit);[url=][/url]

  1.头文件说明:所有模块都要使用头文件module.h,此文件必须包含进来;头文件kernel.h包含了常用的内核函数;头文件init.h包含了宏_init和_exit,它们允许释放内核占用的内存。interrupt.h文件时编写tasklet(关于tasklet的说明可以参考linux中断与异常)必须要用的头文件。
  2.test_init是模块的初始化函数,它必需包含诸如要编译的代码、初始化数据结构等内容,其中的tasklet_init初始化我们自己创建的tasklet,tasklet_schedule函数则是将我们初始化后的tasklet挂到tasklet链表中,并激活软中断来执行我们的tasklet。
  3.test_exit是模块的退出和清理函数。此处可以做所有终止该内核模块时相关的清理工作。
  4.函数module_init()和module_exit()是模块编程中最基本也是必须的两个函数。module_init()向内核注册模块,并调用注册做模块的初始化工作的函数,而module_exit()注销模块并注册模块注销时执行的清理函数
  5.第10行使用了printk()函数,该函数是由内核定义的,功能与C库中的printf()类似,它把要打印的信息输出到终端或系统日志。字符串前面的KERN_ALERT是输出的级别,表示立即在终端输出,可以调用dmesg命令来查看输出。
  有了上面的各个组成,一个模块就算编写好了。

三、 编译模块
编译模块不想编译普通的c文件,直接敲几个命令就可以了,编译模块必须用Makefile文件,而且Makefile文件必须按一定的规则编写,这个和平时编写的Makefile文件不一样。编写内核模块的Makefile文件内容几乎相同的。下面是模版:
[url=][/url]
obj-m += tasklet.o        # 产生tasklet 模块的目标文件CURRENT_PATH := $(shell pwd)   #模块所在的当前路径LINUX_KERNEL := $(shell uname -r)    #Linux内核源代码的当前版本LINUX_KERNEL_PATH := /usr/src/linux-headers-$(LINUX_KERNEL) #Linux内核源代码的绝对路径all:make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules   #编译模块了clean:make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean    #清理[url=][/url]

  除了第一行要把tasklet换成编写的目标模块的.c文件名外,其它都是一样的。
  一切都准备好之后,直接make一下就ok了。

四、 运行模块
运行模块也不能像运行普通程序一样,直接./tasklet来运行,必须通过专门的命令来运行。
  使用$insmod tasklet.ko命令直接将我们的模块插入到内核中,模块被插入内核时就会调用我们注册的初始化函数test_init,用dmesg命令查看输出,可以看到tasklet_handler is running.消息被打印了。
  使用$lsmod命令来查看系统中的模块:


  使用$rmmod tasklet来卸载模块,卸载模块的同时会执行注册函数test_exit,用dmesg可以查看打印消息。

继承事业,薪火相传
返回列表