注:这是当初学习《linux设备驱动程序》的学习笔记,只有提纲挈领的作用,不足之处还请大家多多包涵,多多指点。
Hello world模块
模块能够调用printk是因为在insmod函数装入模块之后,模块就连接到了内核,可以访问内核的公用符号。
printk( KERN_ALERT” Hello world.\n”);
优先级只是一个字符串,如<1>,该字符串置于printk格式字符串的前面。注意:KERN_ALERT之后并不适用逗号。
核心模块和应用程序的对比
² 应用程序在退出时,可以不管资源的释放或者其他的清楚工作,但模块的退出函数却必须仔细撤销初始化函数所做的一切,否则,在系统重新引导之前某些东西就会残留在系统中。
² printk与printf最大的不同在于它缺乏对浮点数的支持。
² 编写模块代码用到的大多数头文件都在include/linux和include/asm目录中,include其他的子目录保存有和特定子系统相关的头文件。
用户空间和内核空间
² 模块运行在所谓的内核空间,而应用程序运行在所谓的用户空间。
² 内核空间和用户空间都有自己的内存映射,也即自己的地址空间。
² 一个驱动程序要执行两种任务:某些函数作为系统调用的一部分而执行,其他函数负责中断处理。
内核中的并发
Linux内核代码(包括驱动程序代码)必须是可重入的。
常见错误:认为只要某段代码没有进入睡眠状态(或者阻塞),就不会产生并发问题。
当前进程
内核代码可通过全局项current来获得当前进程。current在<asm.current.h>中定义,是一个指向struct task_struct的指针,task_struct结构在<linux/sched.h>文件中定义。current指针指向当前正在运行的程序,在open、read等系统调用的执行过程中,当前进程指的是调用这些系统调用的进程。
设备驱动程序只要包含<linux/sched.h>头文件即可引用当前进程。如:
printk(KERN_INFO “The process is \” %s \” (pid %i) \n”, current->comm, current->pid);
current->comm中式当前进程所执行的程序文件的基本名称。
其他的一些细节
内核栈非常小。
内核API中看到具有两个下划线(__)的函数名称。这种函数通常是接口的底层组件,应谨慎使用。
内核代码不能实现浮点数运算。
编译和装载
编译模块
如果我们邀构造的模块名称为module.ko,并由两个源文件(如file1.c和file2.c)生成,则正确的makefile可以编写如下:
obj-m := module.o
module-objs := file1.o file2.o
如果内核源代码树保存在~/kernel-2.6目录中,则用来构造模块的make命令应该是(在包含模块源代码和makefile的目录中键入)
make –C ~/kernel-2.6 M=’pwd’ modules
装载和卸载模块
insmod将模块的代码和数据装入内核,然后使用内核的符号表解析模块中任何为解析的符号。它和ld(链接器)不同,内核不会修改模块的磁盘文件,仅仅修改内存中的副本。
insmod可以接受一些命令行选项,并且可以在加载模块是为其中的整形和字符串型变量赋值。
insmod依赖于定义在kernel/module.c中的一个系统调用。函数sys_init_mudule给模块分配内核内存(vmalloc负责),然后该系统调用将模块正文复制到内存区域,并用内核符号表解析模块中的内核引用,最后调用模块的初始化函数。
modprobe工具:和insmod类似,用来装载模块。和insmod的区别:modprobe会考虑要装载的模块是否引用了一些当前内核不存在的符号,如果有,则在当前模块搜索路径上查找定义了这些符号的其他模块,若找到(即要装载模块所以来的其他模块),则modprobe同时将这些模块装载到内核。insmod在这种情况下会失败,并且在系统日志中记录”unresolved symbols ” 消息。系统日志文件(/var/log/messages)
lsmod程序:列出了当前装载到内核的所有模块。它通过读取/proc/modules虚拟文件来获得这些信息。
版本依赖
linux/version.h自动包含于linux/module.h中,其中的一些宏:
² UTS_RELEASE
扩展为一个描述内核版本的字符串,如”2.6.10”。
² LINUX_VERSION_CODE
扩展为内核版本的二进制表示,版本发行号的每一部分对应一个字节。如2.6.10对应的 是132618(0x02060a)。
² KERNEL_VERSION(major, minor, release)
以组成版本号的三部分为参数,创建证书的版本号。KERNEL_VERSION(2,6,10)扩展为132618。