深入浅出Linux设备驱动编程--Linux内核模块.pdf
上传人:sy****28 上传时间:2024-09-14 格式:PDF 页数:3 大小:82KB 金币:18 举报 版权申诉
预览加载中,请您耐心等待几秒...

深入浅出Linux设备驱动编程--Linux内核模块.pdf

深入浅出Linux设备驱动编程--Linux内核模块.pdf

预览

在线预览结束,喜欢就下载吧,查找使用更方便

18 金币

下载此文档

如果您无法下载资料,请参考说明:

1、部分资料下载需要金币,请确保您的账户上有足够的金币

2、已购买过的文档,再次下载不重复扣费

3、资料包下载后请先用软件解压,在使用对应软件打开

深入浅出Linux设备驱动编程--Linux内核模块Linux设备驱动属于内核的一部分,Linux内核的一个模块可以以两种方式被编译和加载:(1)直接编译进Linux内核,随同Linux启动时加载;(2)编译成一个可加载和删除的模块,使用insmod加载(modprobe和insmod命令类似,但依赖于相关的配置文件),rmmod删除。这种方式控制了内核的大小,而模块一旦被插入内核,它就和内核其他部分一样。下面我们给出一个内核模块的例子:#include<linux/module.h>//所有模块都需要的头文件#include<linux/init.h>//init&exit相关宏MODULE_LICENSE(“GPL”);staticint__inithello_init(void){printk(“Hellomoduleinit\n”);return0;}staticvoid__exithello_exit(void){printk(“Hellomoduleexit\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–ohello.ohello.c由此可见,Linux内核模块的编译需要给gcc指示–D__KERNEL__-DMODULE–DLINUX参数。-I选项跟着Linux内核源代码中Include目录的路径。下列命令将可加载hello模块:insmod./hello.o下列命令完成相反过程:rmmodhello如果要将其直接编译入Linux内核,则需要将源代码文件拷贝入Linux内核源代码的相应路径里,并修改Makefile。我们有必要补充一下Linux内核编程的一些基本知识:内存在Linux内核模式下,我们不能使用用户态的malloc()和free()函数申请和释放内存。进行内核编程时,最常用的内存申请和释放函数为在include/linux/kernel.h文件中声明的kmalloc()和kfree(),其原型为:void*kmalloc(unsignedintlen,intpriority);voidkfree(void*__ptr);kmalloc的priority参数通常设置为GFP_KERNEL,如果在中断服务程序里申请内存则要用GFP_ATOMIC参数,因为使用GFP_KERNEL参数可能会引起睡眠,不能用于非进程上下文中(在中断中是不允许睡眠的)。由于内核态和用户态使用不同的内存定义,所以二者之间不能直接访问对方的内存。而应该使用Linux中的用户和内核态内存交互函数(这些函数在include/asm/uaccess.h中被声明):unsignedlongcopy_from_user(void*to,constvoid*from,unsignedlongn);unsignedlongcopy_to_user(void*to,void*from,unsignedlonglen);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_MESSA