linux设备驱动程序第3,4章笔记

第三章字符设备驱动程序
scull:操作内存的字符设备(任何人都可以编译运行)

scull的设计
编写设备驱动程序的第一步就是定义驱动程序提供给用户程序的能力

主设备号和次设备号
通过访问文件系统的名字访问字符设备

设备文件是特殊文件

主设备号标识设备对应的驱动程序
次设备号只由驱动程序使用,内核其他部分不使用,仅将它传给驱动程序

向系统增加一个驱动程序意味着要赋予他一个主设备号

mknod:创建一个设备节点,而且必须是超级用户才可以

动态分配主设备号
主设备号总是正的,不会和错误码混淆

动态分配由于分配给你的主设备号不能保证是一样,无法实现创建节点

root创建的节点只属于root,默认权限位只允许root对其有写访权限,其他的只有读权限

分配主设备号最佳方法是:默认采用动态分配,同时留给你在加载时,甚至是编译时,指定主设备号的余地

从系统中卸载一个模块时,应该释放主设备号

参数要释放主设备号和相应的设备名,

注销资源失败后果很不好

当卸载模块时,却又无法注销主设备号时,此情况无法恢复,即使专门写一个补救模块也没用

除了卸载模块,还要经常在卸载驱动程序时删除设备节点

每次内核调用一个设备驱动程序,他都告诉驱动程序他正在操作那个程序

主设备号和次设备号和在一起构成一个数据类型并用来识别某些设备

文件操作

file操作
file与用户程序中的FILE没有任何联系

file:代表打开的文件。文件关闭后,内核释放这个数据结构

open:驱动程序用来为以后的操作完成初始化准备工作的。还可以增加设备计数,以便防止文件在关闭前模块被移出内核

首先要识别要操作的是哪个设备

驱动程序从来都不知道被打开的设备名,只知道设备号

用来存放内存区的数据结构是Scull_Dev

release:与open相反,也称为close。使用计数减一非常必要,这样内核才会卸载模块

dup和fork都会在不调用open的情况下,将一个打开文件复制为两个,但每一个都会在程序终止时关闭

如果open没有调用,close也不会调用

scull使用的内存,也称为设备

无论何时驱动程序都需要一个随意的数值或这个数值与策略相关,

所选的默认值是为了优化中等规模的系统和大数据量使用

读写scull设备意味着要完成内核空间和用户进程空间的数据传输

指针只在当前地址空间操作,而驱动程序运行在内核空间,数据缓冲区则在用户空间

设备驱动程序的主要作用:管理设备(内存空间)和应用(用户空间)间的数据传输

scull中的read和write的驱动程序代码需要完成到用户空间和来自用户空间的整个数据段的复制

读:将数据从设备复制到用户空间
写:将数据从用户空间复制到设备

成功传输,返回值是成功传输的字节计数。如果为0,说明已经到达了文件尾
失败传输,返回值是负值

wirte:值为0,则什么也没写

根据你向scull写了多少数据,用free命令可以看到空闲内存的缩减和扩增

第四章调试技术
最一般的调试技术是监控,就是在应用程序内合适的点加上printf调用,当你调用内核代码的时候,可以用printk完成

根据记录集,内核将消息打印到当前文本控制台上

printk函数将消息写到一个循环缓冲区,然后唤醒任何等待消息的进程。如果循环缓冲区满了,就绕道缓冲区的开始处填写新的数据,覆盖旧数据

可以在任何地方调用printk,甚至在中断处理函数里也可以调用,而对数据量大小没有限制,唯一的缺点就是可能会丢失数据

好的编程技巧要在灵活性和高效性间找到平衡点

(1)预编译器条件只到编译时运行,必须重新编译程序来打开或是关闭消息
(2)使用c语言,他在运行时执行,可以让你在程序执行期间打开或关闭消息

syslogd:会一直保持刷新他的输出文件,每打印一次都要磁盘操作,所以过量使用printk会降低系统性能

在你需要信息时,通过查询系统获得相关信息,而不是不断地产生数据

/proc文件系统
此文件系统与任何设备都没有关系,这里的文件都是在被读取时由内核创建的,都是普通的文本文件,可被人,工具系统理解

可以动态创建i节点,允许用户模块为方便信息检索创建入口点

如果文件节点仅仅是为了要读,则简单一些

唯一的限制就是所写的数据不能超过PAGE_SIZE个字节

如果需要写超过一个页面的程序,必须依赖与功能键全的文件去实现

ioctl
一个系统调用,通常是一个指针

作为替代/proc的系统,可以调试实现若干个系统

ioctl不限制返回数据的大小

当调试结束后,命令任然可以保留在驱动程序中

但是模块会大一些

通过监视进行调试(查明运行错误是最有用)
用调试器一步一步跟踪它的函数,插入打印语句,或strace运行程序(当只是查看内核代码非常有用)

strace:可以实现所有系统调用,不仅可以显示调用,还可以显示调用的参数,以符号的方式显示返回值;从内核接收方式

故障通常会导致当前进程的终止,但系统继续运行

内核行为异常会在显示台显示一些有用的信息

大部分错误都是指针使用不正确引起的,会导致oops消息

oops显示故障时的处理器状态,模块cpu寄存器内容,页描述附表的内容

使用ksymoops
oops:显示十六进制,此系统将数值地址转为内核形式,但只限PC上的oops

objdump:查看失败前的指令

oops程序由C语言构成

调试模块时,将寄存器和堆栈解码非常有益,如果被调试的所有模块符号都开发出来更有帮助

klogd:可以在oops存放到记录文件前对oops解码

当oops发生在内核时,看守进程正确的解码指令指针。并不返汇编编码

系统挂起
如果系统挂起了,没有消息可以打印出来

处理系统挂起有两个方法:(1)防患于未然(2)亡羊补牢

在策略点上插入schedule可以防止死循环

即使系统挂起了,消息也会打印到控制台上

键盘若不接受输入:(1)从网络登录到系统,杀掉错误(2)重新设置键盘

调试器一步步跟踪代码,查看变量和寄存器的值

在当前版本的内核可以查看修改变量

gdb
更适合调试内核,而不是模块

可以通过gdb,查看内核变量

可以命令反汇编函数

kdebug
是使用gdb“远程调试接口”与内核调试的小工具

无需打补丁或者重新编译

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值