2.Linux 内核模块

 2.Linux 内核模块

Linux 设备驱动属于内核的一部分,Linux 内核的一个模块可以以两种方式被编译和加
载:
(1)直接编译进Linux 内核,随同Linux 启动时加载;
(2)编译成一个可加载和删除的模块,使用insmod 加载(modprobe 和insmod 命令类
似,但依赖于相关的配置文件),rmmod 删除。这种方式控制了内核的大小,而模块一旦被
插入内核,它就和内核其他部分一样。
下面我们给出一个内核模块的例子:
#include <linux/module.h> //所有模块都需要的头文件
#include <linux/init.h> // init&exit 相关宏
MODULE_LICENSE("GPL");

static int __init hello_init (void)
{
printk("Hello module init\n");
return 0;
}
static void __exit hello_exit (void)
{
printk("Hello module exit\n");

}
module_init(hello_init);
module_exit(hello_exit);
分析上述程序,发现一个Linux 内核模块需包含模块初始化和模块卸载函数,前者在
insmod 的时候运行,后者在rmmod 的时候运行。初始化与卸载函数必须在宏module_init
和module_exit 使用前定义,否则会出现编译错误。
程序中的 MODULE_LICENSE("GPL")用于声明模块的许可证。
如果要把上述程序编译为一个运行时加载和删除的模块,则编译命令为:
gcc –D__KERNEL__ -DMODULE –DLINUX –I /usr/local/src/linux2.4/include -c –o hello.o
hello.c
由此可见,Linux 内核模块的编译需要给gcc 指示–D__KERNEL__ -DMODULE
–DLINUX 参数。-I 选项跟着Linux 内核源代码中Include 目录的路径。
下列命令将可加载 hello 模块:
insmod ./hello.o
下列命令完成相反过程:
rmmod hello
如果要将其直接编译入Linux 内核,则需要将源代码文件拷贝入Linux 内核源代码的相
应路径里,并修改Makefile。
我们有必要补充一下 Linux 内核编程的一些基本知识:

内存
在 Linux 内核模式下,我们不能使用用户态的malloc()和free()函数申请和释放内存。进
行内核编程时,最常用的内存申请和释放函数为在include/linux/kernel.h 文件中声明的
kmalloc()和kfree(),其原型为:
void *kmalloc(unsigned int len, int priority);
void kfree(void *__ptr);
kmalloc 的priority 参数通常设置为GFP_KERNEL,如果在中断服务程序里申请内存则
要用GFP_ATOMIC 参数,因为使用GFP_KERNEL 参数可能会引起睡眠,不能用于非进程
上下文中(在中断中是不允许睡眠的)。
由于内核态和用户态使用不同的内存定义,所以二者之间不能直接访问对方的内存。而
应该使用Linux 中的用户和内核态内存交互函数(这些函数在include/asm/uaccess.h 中被声
明):
unsigned long copy_from_user(void *to, const void *from, unsigned long n);
unsigned long copy_to_user (void * to, void * from, unsigned long len);
copy_from_user、copy_to_user 函数返回不能被复制的字节数,因此,如果完全复制成
功,返回值为0。
include/asm/uaccess.h 中定义的put_user 和get_user 用于内核空间和用户空间的单值交互
(如char、int、long)。
这里给出的仅仅是关于内核中内存管理的皮毛,关于 Linux 内存管理的更多细节知识,
我们会在本文第9 节《内存与I/O 操作》进行更加深入地介绍。

输出
在内核编程中,我们不能使用用户态 C 库函数中的printf()函数输出信息,而只能使用
printk()。但是,内核中printk()函数的设计目的并不是为了和用户交流,它实际上是内核的
一种日志机制,用来记录下日志信息或者给出警告提示。

每个printk 都会有个优先级,内核一共有8 个优先级,它们都有对应的宏定义。如果未
指定优先级,内核会选择默认的优先级DEFAULT_MESSAGE_LOGLEVEL。如果优先级数
字比int console_loglevel 变量小的话,消息就会打印到控制台上。如果syslogd 和klogd 守护
进程在运行的话,则不管是否向控制台输出,消息都会被追加进/var/log/messages 文件。klogd
只处理内核消息,syslogd 处理其他系统消息,比如应用程序。
模块参数
2.4 内核下,include/linux/module.h 中定义的宏MODULE_PARM(var,type) 用于向模块
传递命令行参数。var 为接受参数值的变量名, type 为采取如下格式的字符串
[min[-max]]{b,h,i,l,s}。min 及max 用于表示当参数为数组类型时,允许输入的数组元素的个
数范围;b:byte;h:short;i:int;l:long;s:string。
在装载内核模块时,用户可以向模块传递一些参数:
insmod modname var=value

如果用户未指定参数,var 将使用模块内定义的缺省值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值