之前一直长期做windows驱动开发,但是一直将这些技术知识点进行整理和总结,最近又开始做一套新的驱动,于是就打算趁这个机会,将一些windows驱动开发的技术知识系统性的整理出来。
目录如下:
windows驱动开发知识-设计目标
windows驱动开发知识-WDM和WDF
windows驱动开发知识-内核组件
windows驱动开发知识-设备栈
windows驱动开发知识-内存概述
windows驱动开发知识-I/O请求
windows驱动开发知识-内核线程
windows驱动开发知识-硬件中断
windows驱动开发知识-软件中断
windows驱动开发知识-寄存器
windows驱动开发知识-DMA
============================================================
windows驱动开发基础知识
windows 驱动开发经历了许多版本,在2000和xp的时候,使用的是DDK开发包;在win 7时候使用的是WinDDK开发包;在win 8之后,微软在Visual Studio2012中正式集成了winddk,但是最终直到Visual Studio 2015开始,才比较完整在IDE中集成了驱动开发工具。
windows内核一般也叫NT内核,从5.0开始,才真正脱离了之前MSDOS的架构,这是有史以来兼容性最好的系统内核设计体系,很多基于NT 5.0设计的驱动程序,仍然可以直接在NT 10.0上运行。
WDM驱动模型贯穿整个NT 5.0~NT10各个版本的驱动设计中,后面新出现的WDF框架是在WDM驱动模型之上进行的封装,大大提高了开发效率和降低了开发难度。以win 11来讲,WDM和WDF框架均可以开发这个平台下的驱动程序,不过,一般建议使用WDF框架,毕竟对于一些常见的驱动程序来说WDF框架非常友好。
和认知不一样的是,WDM和WDM都是面向对象的开发模型,这和内核有关,虽然windows内核几乎都是使用C语言开发的,但内核的设计思想是面向对象的,驱动被认为是内核链接的动态链接库。
驱动程序的后缀名一般是sys或者dll,它们都是PE结构,这一点和应用程序并无区别,在驱动编程中会更加关注本质而非形式-无论QT还是MFC、C或者VB、com组件还是exe,最终都会以汇编二进制的形式去看待,故对于驱动开发来说,了解汇编是必须的。
驱动程序一般是"驱动“硬件为目的,它们架构于ACPI之上,是最靠近系统底层的程序之一,内核本身设计为HAL、微内核、执行体三层,HAL仅仅提供硬件抽象的能力,主要的硬件功能几乎都是由驱动程序以DLL的方式,被内核加载到地址空间中,为执行体层提供I/O服务,这些服务最终以IRP在内核和应用层之间传递,故在应用层,控制硬件是一件看起来很简单的事情,但是实际上是一件很复杂的事情。
例如USB设备插入电脑:
1. 当接口电路接通时,ACPI会收到一个接通信号,这个信号传递到PCI总线,PCI总线又将其传递到USBHub,USBHub检测到这个电源信号,会创建一个物理设备对象,同时ACPI会主动向USB设备供电,保证后续的通讯正常;
2. 这个物理设备对象创建后,USB总线会从默认的USB端点读取描述符,根据描述符的信息,USB总线会根据这些信息生成一个硬件ID,然后USB总线会根据硬件ID来判断系统是否有PID和VID相匹配的驱动程序记录,在HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum中查看;
3. 如果有,那么将对应的驱动程序加载到内核中,然后USB总线通过PNP管理器调用对应驱动的AddDevice事件;在AddDevice最重要的一步是创建设备栈并初始化I/O派发例程;
4. 当AddDevice例程调用是,[NP管理器也会通知应用层的窗口管理器,应用层编程中,可以注册接收WM_DEVICECHANGE消息,如果注册了这个消息,那么窗口管理器在收到设备插入的事件时,就会通知对应的窗口;
5. windows会话管理器本身也会受到这个事件通知,然后这个通知就在系统托盘处显示"USB插入信息",这个过程中我们甚至可以看到系统是如何匹配这些设备的驱动过程;
但是在应用层,我们只需要注册WM_DEVICECHANGE即可收到通知,并会在设备安装完驱动之后才会收到通知。