系统平台: Ubuntu 14.04 LTS
(linux mint mate14.04)
Linux version 3.13.0-37-generic (buildd@kapok) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #64-Ubuntu SMP Mon Sep 22 21:28:38 UTC 2014
如无特别说明,本系列文章均使用以上平台。
一 linux内核模块特点
内核模块:Linux内核本身是很庞大的一个结构,需要的组件很多。编译内核时,用户可以把所有的代码编译进内核,
但这样会引起两个问题:
1.内核过大.
2. 当需要添加或者删除内核时,需要重新再编译内核.
所以为了解决问题,有了内核模块的概念。模块并不编译到内核中,编译后存放在指定的目录,当需要使用时动态加载。
下边给出一个例子:
/*******************************************
*Title : study linux device driver(1)---module
*Author: beijiwei@qq.com
*Date : 2015.01.19
*
******************************************/
#include<linux/module.h>
#include<linux/init.h>
static int __init abx_init(void)
{
pr_err("%s enter \n",__func__);
printk("hello world!\n");
return 0;
}
static void __exit abx_exit(void)
{
pr_err("%s exit \n",__func__);
}
module_init(abx_init);
module_exit(abx_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("beijiwei@qq.com>");
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("Abs Driver");
再来一个Makefile,注意M 大写:
#Title : for helo module build
#Author: beijiwei@qq.com
#Date : 2015.01.19
obj-m :=abx.o
#abx-objs :=hello_dev.o hello_drv.o
Kernel_DIR:=/usr/src/linux-headers-3.13.0-37-generic/
all:
make -C $(Kernel_DIR) M=`pwd` modules
clean:
make -C $(Kernel_DIR) M=`pwd` modules clean
rm -f modules.order
通过 -C指明系统上的内核体系路径,通过 M=指明模块源文件路径,从而实现编译过程。
编写完毕后在代码目录下执行“make”命令,就会产生abx.ko文件,在PC上
通过命令“insmod abx.ko”,插入模块,之后,可以在 /sys/modules 下看到abx 文件夹
通过命令“lsmod”查看当前的所有装载的模块,
通过命令“rmmod abx”卸载该模块。
并且,加载时shell dmesg 会输出 “enter!”,卸载时会输出“exit”。
上面的程序包含了三个知识点:
1.内核初始化函数:
static int __init abx_init(void) //内核初始化函数
{
}
module_init(abx_init); //指定初始化函数
1)初始化函数是在模块加载时自动被调用,执行相关的初始化工作。
2)static和__init都是可以不加的,因为初始化函数除了加载时执行外没有别的用处,加上static只是声明一下,该函数只能在模块内部使用。而加上__init后,它暗示内核该函数仅在初始化时使用,所以在模块被装载后,模块装载器就会把该函数扔掉,释放占用的内存空间。
3)但是moudle_init()是必须要的,因为这样才能让模块加载器知道这是个初始化函数,没有这一步,函数就不会得到调用。
4)初始化函数成功返回0,失败返回对应的错误码。
2.内核清除函数:
static void __exit abx_exit(void)//内核清除函数
{
}
module_exit(abx_exit); //指定清除函数
1)内核清除函数是在模块卸载是自动被调用,执行相关的清除工作。
2)同上,static和__exit都是可以不加的,但如果加上__exit,模块直接编译进内核或者不允许卸载,被标志为__exit的函数会被自动丢弃掉,不会使用。
3)module_exit是必须的,因为这样内核才能找到清除函数。
4)清除函数的没有返回值。
5)一个没有定义清除函数的模块,是不允许被加载的。
3.模块的描述性定义:
MODULE_LICENSE("GPL"); //指定代码使用的许可证
MODULE_AUTHOR("xiaobai"); //指定作者
MODULE_VERSION("1.0"); //指定代码修订号
1)以上的都是一些都该模块的描述,除了上面的还有MODULE_ALIAS(模块的别名)MODULE_DESCRIPTION(描述用途)等。
2)MODULE_LICENSE一般都是要写的,告诉内核该程序使用的许可证,不然在加载时它会提示该模块污染内核。
3)MODULE_声明可以声明在源代码任意位置,但习惯放在代码的最后。