1、最简单的内核模块例子
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
static int __init hello_init(void)
{
printk(KERN_INFO "Hello world\n");
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "Goodbye world\n");
}
module_init(hello_init);
module_exit(hello_exit);
注释::
•
static int __init hello_init(void)
•
static void __exit hello_exit(void)
–
Static声明,因为这种函数在特定文件之外没有其它意义
– __init标记,
该函数只在初始化期间使用。模块装载后,将该函数占用的内存空间释放
– __exit标记
该代码仅用于模块卸载。
•
Init/exit
– 宏:module_init/module_exit
– 声明模块初始化及清除函数所在的位置
– 装载和卸载模块时,内核可以自动找到相应的函数
module_init(hello_init);
module_exit(hello_exit);
•
Makefile文件
obj-m := hello.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd)
modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd)
clean
•
Module includes more files
obj-m:=hello.o
hello-objs := a.o b.o
2、装载和卸载模块相关命令
– lsmod
– insmod hello.ko
– rmmod hello.ko
•
有些模块需要传递一些参数
•
参数在模块加载时传递
#insmod hello.ko test=2
•
参数需要使用module_param宏来声明
module_param的参数:变量名称,类型以及访问许可掩码
•
支持的参数类型
Byte, short, ushort, int, uint, long, ulong, bool,
charp
Array (module_param_array(name, type, nump, perm)
例子::
#include
<linux/kernel.h>
#include
<linux/module.h>
#include <linux/init.h>
#include
<linux/moduleparam.h>
static int test;
module_param(test, int, 0644);
static int __init hello_init(void)
{
printk(KERN_INFO “Hello world test=%d \n” ,
test);
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "Goodbye world\n");
}
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Test");
MODULE_AUTHOR("xxx");
module_init(hello_init);
module_exit(hello_exit);
3、
•
/proc文件系统,这是内核模块和系统交互的两种主要方式之一。
•
/proc文件系统也是Linux操作系统的特色之一。
•
/proc文件系统不是普通意义上的文件系统,它是一个伪文件系统。
•
通过/proc,可以用标准Unix系统调用(比如open()、read()、write()、
ioctl()等等)访问进程地址空间
•
可以用cat、more等命令查看/proc文件中的信息。
•
用户和应用程序可以通过/proc得到系统的信息,并可以改变内核的某些参数。
•
当调试程序或者试图获取指定进程状态的时候,/proc文件系统将是你强有力的支持者。通过它可以创建更强大的工具,获取更多信息。
•
create_proc_entry() 创建一个文件
•
proc_symlink() 创建符号链接
•
proc_mknod()
创建设备文件
•
proc_mkdir()
创建目录
•
remove_proc_entry() 删除文件或目录
4、 模块引用计数器
Linux2.4中在linux/module.h中定义了三个宏来维护实用计数:
__MOD_INC_USE_COUNT
当前模块计数加一
__MOD_DEC_USE_COUNT
当前模块计数减一
__MOD_IN_USE 计数非0时返回真
在Linux2.6中,模块引用计数器由系统自动维护,所以程序中有关这些宏都可以注释掉。
•
关于符号导出列表(list of exported symbols)
Linux2.4中会用EXPORT_NO_SYMBOLS宏,来表示不想导出任何变量或函数。
在Linux2.6中这个宏也已经消失。系统默认为不导出任何变量或函数。
5、模块程序编译方法的改变
Linux2.4中命令为:
gcc
–Wall –DMODULE –D__KERNEL__ -DLINUX –c 源文件名.c
其中:
__KERNEL__:
即告诉头文件这些代码将在内核模式下运行
MODULE:
即告诉头文件要给出适当的内核模块的定义
LINUX:
并非必要
-Wall:
显示所有warning信息。
•
Linux2.6中必须写makefile。通过make命令编译程序。
Linux2.6中makefile的写法:(以helloworld为例)
//Makefile obj-m += hello.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make
-C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
*
注意:all下一行需要有一个“Tab”键,不要写成空格或略去,不然系统无法识别,报错:nothing
to be done for “all”。