双重设备端口驱动程序,如图2.6中所示的键盘和辅助设备控制器的(i8042)驱动程序, 如果每个设备使用不同的中断向量,必须创建设备特定的中断对象。写这样的驱动程序 时,要么为每个设备实现单独的ISR,要么两种设备实现单一的ISR。 2.6.2设备对象的注意事项 设计内核模式驱动程序,应当遵从下列的事项: 除某些微端口驱动程序之外,所有的驱动程序必须创建命名的设备对象,以代表每个 物理、逻辑、或者虚拟设备,这些设备可能是I/0请求的目标 最低层驱动程序,例如PnP硬件总线驱动程序,为每个它控制的设备创建一个物理设 备对象(PD0)。中间驱动程序,例如PmP功能驱动程序,创建一种功能设备对象 (FDO) 例如,替换的并行端口或者串行驱动程序应该为每个端口创建一个物理设备对象。相 比之下,描述机器中的每个硬盘为大硬盘的新虚拟硬盘驱动程序应该创建一个单独功 能的设备对象和一定数量的额外功能的设备对象,前者描述它的硬盘,后者为位于这 个中间层驱动程序之上的文件系统描述磁盘分区。 驱动程序在其 AddDevice例程中创建设备对象,这个例程在设备列举之后被PnP管理 器调用 对于大多数最低层和中间层驱动程序,每个设备对象的设备扩展是每一驱动程序的主 要的(并且只是经常地)全局数据存储区域。许多驱动程序在驱动程序定义的设备扩 展(属于一个或多个驱动程序创建的设备对象)中维护设备状态和驱动程序需要的所 有其他设备特定的数据和资源 对于某些种类的数据,IRP中驱动程序特定的I/0栈位置被认为是操作特定的本地存 储区域
26 双重设备端口驱动程序,如图 2.6 中所示的键盘和辅助设备控制器的(i8042)驱动程序, 如果每个设备使用不同的中断向量,必须创建设备特定的中断对象。写这样的驱动程序 时,要么为每个设备实现单独的 ISR,要么两种设备实现单一的 ISR。 2.6.2 设备对象的注意事项 设计内核模式驱动程序,应当遵从下列的事项: ▪ 除某些微端口驱动程序之外,所有的驱动程序必须创建命名的设备对象,以代表每个 物理、逻辑、或者虚拟设备,这些设备可能是 I/O 请求的目标。 最低层驱动程序,例如 PnP 硬件总线驱动程序,为每个它控制的设备创建一个物理设 备对象(PDO)。中间驱动程序,例如 PnP 功能驱动程序,创建一种功能设备对象 (FDO)。 例如,替换的并行端口或者串行驱动程序应该为每个端口创建一个物理设备对象。相 比之下,描述机器中的每个硬盘为大硬盘的新虚拟硬盘驱动程序应该创建一个单独功 能的设备对象和一定数量的额外功能的设备对象,前者描述它的硬盘,后者为位于这 个中间层驱动程序之上的文件系统描述磁盘分区。 驱动程序在其 AddDevice 例程中创建设备对象,这个例程在设备列举之后被 PnP 管理 器调用。 ▪ 对于大多数最低层和中间层驱动程序,每个设备对象的设备扩展是每一驱动程序的主 要的(并且只是经常地)全局数据存储区域。许多驱动程序在驱动程序定义的设备扩 展(属于一个或多个驱动程序创建的设备对象)中维护设备状态和驱动程序需要的所 有其他设备特定的数据和资源。 对于某些种类的数据,IRP 中驱动程序特定的 I/O 栈位置被认为是操作特定的本地存 储区域
第3章系统定义的对象和对驱动程序的支 持 本章包含下列的信息: 3.1系统组成部分和分层内核模式驱动程序 3.1.1操纵系统定义的对象的支持例程 3.1.2存储系统定义的对象 3.2设备对象和设备扩展 3.2.1定义设备扩展 3.2.2创建设备对象和设备扩展 3.2.3初始化驱动程序特定的设备对象和设备扩展 3.2.4设置用户缓冲区的访问 3.2.4.1使用缓冲I/0 3.2.4.2使用直接I/0 3.2.4.3使用非直接也非缓冲I/0 3.3适配器对象和DMA 3.3.1映射寄存器 3.3.2获取适配器对象 3.3.3拆分传输请求 3.3.4使用系统DMA 3.3.4.1基于包的系统DMA 3.3.4.2公用缓冲区的系统DMA 3.3.5使用总线控制器DMA 3.3.5.1基于包的总线控制器DMA 3.3.5.2公用缓冲区的总线控制器DMA 3.3.6执行分散/收集DMA 3.4控制器对象 3.4.1使用控制器扩展创建控制器对象 3.4.2为1/0操作分配控制器对象 3.5中断对象 3.5.1获得系统指定中断向量、DIRL、和处理器掩码 3.5.2注册ISR 3.6DPC对象 3.6.1注册和排队 DpcForlsr例程 3.6.2注册和排队 CustomDpc例程 3.7带有相关DPC的定时器对象 3.7.1注册和激活 LoRimer例程 3.7.2注册和排队 CustomTimerDpc例程 3.8设备队列对象和互锁队列 3.8.1设置设备队列对象和排队 3.8.2设置一个互锁队列和排队 3.9内核调度者对象
27 第3章 系统定义的对象和对驱动程序的支 持 本章包含下列的信息: 3.1 系统组成部分和分层内核模式驱动程序 3.1.1 操纵系统定义的对象的支持例程 3.1.2 存储系统定义的对象 3.2 设备对象和设备扩展 3.2.1 定义设备扩展 3.2.2 创建设备对象和设备扩展 3.2.3 初始化驱动程序特定的设备对象和设备扩展 3.2.4 设置用户缓冲区的访问 3.2.4.1 使用缓冲 I/O 3.2.4.2 使用直接 I/O 3.2.4.3 使用非直接也非缓冲 I/O 3.3 适配器对象和 DMA 3.3.1 映射寄存器 3.3.2 获取适配器对象 3.3.3 拆分传输请求 3.3.4 使用系统 DMA 3.3.4.1 基于包的系统 DMA 3.3.4.2 公用缓冲区的系统 DMA 3.3.5 使用总线控制器 DMA 3.3.5.1 基于包的总线控制器 DMA 3.3.5.2 公用缓冲区的总线控制器 DMA 3.3.6 执行分散/收集 DMA 3.4 控制器对象 3.4.1 使用控制器扩展创建控制器对象 3.4.2 为 I/O 操作分配控制器对象 3.5 中断对象 3.5.1 获得系统指定中断向量、DIRQL、和处理器掩码 3.5.2 注册 ISR 3.6 DPC 对象 3.6.1 注册和排队 DpcForIsr 例程 3.6.2 注册和排队 CustomDpc 例程 3.7 带有相关 DPC 的定时器对象 3.7.1 注册和激活 IoTimer 例程 3.7.2 注册和排队 CustomTimerDpc 例程 3.8 设备队列对象和互锁队列 3.8.1 设置设备队列对象和排队 IRP 3.8.2 设置一个互锁队列和排队 IRP 3.9 内核调度者对象
3.9.1定时器对象 3.9.2事件对象 3.9.3信号量对象 3.9.4互斥体对象 3.9.5调度者对象上线程等待的 Alert和APC的处理 3.10回调对象 3.10.1定义回调对象 3.10.2使用驱动程序定义的回调对象 3.10.3使用系统定义的回调对象 所有内核模式驱动程序使用某些系统定义的对象。例如,所有的驱动程序(除某些微端口 驱动程序之外)必须创建并安装设备对象,以代表它为其处理IRP的每个逻辑、虚拟、和/ 或物理的设备。 仅仅某些种类的驱动程序被要求使用特殊的系统定义的对象。例如,一个给定的驱动程序 是否使用适配器对象取决于其设备是否使用DMA 这章描述内核模式驱动程序使用的系统定义的对象。除了表明的以外,这个信息适用于 Windows2000和WM驱动程序。哪个对象适合于特定设备类型的细节,参见DDK中设备特 定的文档 31系统组成部分和分层内核模式驱动程序 图3.1总结了分层的内核模式驱动程序链和系统组件之间的联系,这些系统组件定义了这 些驱动程序能调用哪些支持例程。 图3.1对驱动程序的可执行组件支持 也可参看《 Windows2000驱动程序开发参考》卷2,得到关于对最低层和中间层驱动程序 有用的支持例程的细节。 分层的驱动程序链中的驱动程序的数目有些依赖于设备的性质。例如,SCSI海量存储设备 的系统驱动程序形成至少三个驱动程序的链:SCSI类、对应于中间层类的端口驱动程序和 图3.1中所示的最低层物理设备驱动程序,并且至少一个文件系统驱动程序在每个类驱动 程序上被分层。特定的HBA(宿主总线适配器)的SCSI微端口驱动程序被认为是SCSI端 口驱动程序的一部分。 此外,如果用户能够分区镜像,或者创建带或卷集,系统提供的灾难恢复的磁盘驱动程 序, fdisk,可以在SCSI磁盘类驱动程序和文件系统驱动程序之间被分层。 fdisk驱动 程序是可选的,但是它符合图3.1中显示的逻辑/虚拟的中间层设备驱动程序。 3.1.1操纵系统定义的对象的支持例程 最低层驱动程序有与较高层驱动程序不同的标准驱动程序例程,所以图3.1中显示了与硬 件和能使用这些对象的最低层驱动程序接近的某些对象(中断、控制器、和适配器)。硬 件抽象层(HAL)为I/0管理器、内核、电源管理器和许多驱动程序提供平台特定的支持。 所有驱动程序也能调用由I/0管理器提供的支持例程,以获取和提供有关它们的设备的信 息,并在它们的命名的设备对象与子系统特定的名字(针对设备)之间创建符号联接,保
28 3.9.1 定时器对象 3.9.2 事件对象 3.9.3 信号量对象 3.9.4 互斥体对象 3.9.5 调度者对象上线程等待的 Alert 和 APC 的处理 3.10 回调对象 3.10.1 定义回调对象 3.10.2 使用驱动程序定义的回调对象 3.10.3 使用系统定义的回调对象 所有内核模式驱动程序使用某些系统定义的对象。例如,所有的驱动程序(除某些微端口 驱动程序之外)必须创建并安装设备对象,以代表它为其处理 IRP 的每个逻辑、虚拟、和/ 或物理的设备。 仅仅某些种类的驱动程序被要求使用特殊的系统定义的对象。例如,一个给定的驱动程序 是否使用适配器对象取决于其设备是否使用 DMA。 这章描述内核模式驱动程序使用的系统定义的对象。除了表明的以外,这个信息适用于 Windows 2000 和 WDM 驱动程序。哪个对象适合于特定设备类型的细节,参见 DDK 中设备特 定的文档。 3.1 系统组成部分和分层内核模式驱动程序 图 3.l 总结了分层的内核模式驱动程序链和系统组件之间的联系,这些系统组件定义了这 些驱动程序能调用哪些支持例程。 图 3.l 对驱动程序的可执行组件支持 也可参看《Windows 2000 驱动程序开发参考》卷 2,得到关于对最低层和中间层驱动程序 有用的支持例程的细节。 分层的驱动程序链中的驱动程序的数目有些依赖于设备的性质。例如,SCSI 海量存储设备 的系统驱动程序形成至少三个驱动程序的链:SCSI 类、对应于中间层类的端口驱动程序和 图 3.1 中所示的最低层物理设备驱动程序,并且至少一个文件系统驱动程序在每个类驱动 程序上被分层。特定的 HBA(宿主总线适配器)的 SCSI 微端口驱动程序被认为是 SCSI 端 口驱动程序的一部分。 此外,如果用户能够分区镜像,或者创建带或卷集,系统提供的灾难恢复的磁盘驱动程 序,ftdisk,可以在 SCSI 磁盘类驱动程序和文件系统驱动程序之间被分层。ftdisk 驱动 程序是可选的,但是它符合图 3.1 中显示的逻辑/虚拟的中间层设备驱动程序。 3.1.1 操纵系统定义的对象的支持例程 最低层驱动程序有与较高层驱动程序不同的标准驱动程序例程,所以图 3.1 中显示了与硬 件和能使用这些对象的最低层驱动程序接近的某些对象(中断、控制器、和适配器)。硬 件抽象层(HAL)为 I/O 管理器、内核、电源管理器和许多驱动程序提供平台特定的支持。 所有驱动程序也能调用由 I/O 管理器提供的支持例程,以获取和提供有关它们的设备的信 息,并在它们的命名的设备对象与子系统特定的名字(针对设备)之间创建符号联接,保
存在注册表中。最低层驱动程序也能调用 LoXxx和/或 TxxX支持例程,以获得和设置注 册表中的配置信息。更多的信息参见《既插即用、电源管理和安装设计指南》的第4部 分,第2章“注册表中的驱动程序信息” 与I/0管理器类似,安全参考监视器( Security Reference Monitor)、配置管理器 ( Configuration Manager)、对象管理器、过程结构、内存管理器、运行支持和内核组 件,每个都定义一组不透明的对象类型和数据结构。驱动程序只能通过调用适当的内核模 式支持例程来使用这些对象和数据结构 如图3.1所示,最低层(设备)和中间层驱动程序的作者可以忽略本地过程调用(LPC)组 件。只有某些最高层的驱动程序调用由安全组件提供的支持例程。在IRP被送到较低层的 驱动程序之前,I/0管理器或者文件系统驱动程序执行任何必要的进程内通信和安全访问 检査。I/0管理器和对象管理器也在把IRP发送到低层驱动程序之前解析符号联接。 如图3.1所示,I/0管理器为操纵由其他组件定义的某些对象和数据结构提供支持例程 包括符号链接对象、中断对象、DPC对象、定时器对象和内存描述符表(MDL)。这些 LoXxX支持例程帮助实现某些标准驱动程序例程,并且映射缓冲区,这可以与驱动程序定 制的被发往较低层驱动程序的IRP相关。大多数驱动程序仅仅要求 IoXxx支持例程做下列 事情中的一些: 为设备注册标准ISR( IoConnectInterrupt),以及当设备被移走的时候注销ISR (loDisconnectInterrupt 注册标准 DpcForlsr例程( IoInitializedpcRequest),并且从它的ISR中向驱动程 序的 DpcForlsr例程请求一个调用( IoRequestDpc) 注册标准 tImer例程( loInitializetimer),并且能够启用或禁止使每秒对 loRimer例程的调用(分别是 loStartTimer和 loStopTimer)。 将一个已经被与某个输入IRP相关的ML映射的过大的缓冲区拆分成较小的映射的缓 冲区,从而使的驱动程序能在具有有限数据传输能力的设备上进行DMA操作。 除了文件系统驱动程序,当它们调用 IoCreateDevice时,I/0管理器也为驱动程序创建的 每个设备对象安装一个相关的设备队列。它也提供这样的支持例程,驱动程序调用这样的 支持例程以拥有发往它们的 Startle例程的IRP。 loStart Packet和 loStartNext Packet例 程根据驱动程序的需要调用内核的设备队列支持例程。 然而,驱动程序如果必要的话能调用许多I/0管理器调用的相同的内核支持例程。取决于 驱动程序的设计和它的设备,驱动程序能创建 ■定时器对象和能明确地被排队作为 CustomTimerDpc例程的相关DPC对象。例如,如果 驱动程序的设备要求可变的超时间隔或者比每秒一次更精细的间隔,驱动程序可能拥 有 CustomTimerDpc,而非 loRimer例程 个或多个DPC对象和来自ISR明确地排队驱动程序提供的 Cus tomDpc例程。例如, 一个串口驱动程序可以排队一个 CustomDpc,它可以在它的ISR检测到设备错误的时 候取消未决的I/O请求。 设备专用线程和工作者线程在其上回调例程的定时器对象能等待驱动程序指定的时间 间隔。创建它们自己设备专用系统线程的驱动程序,诸如系统软盘驱动程序,也能有 它们的线程来等待内核定义事件、信号量,或者可能有互斥体,就向最高层驱动程序 的工作线程能回调例程那样。驱动程序能通过调用 Ps CreateSystemThread来创建设备 专用线程,并能使用 PsTerminateSystemThread释放这样的线程 附加的设备队列对象。例如,SCSI端口驱动程序(参见在线DDK中“ Storage Drivers and Device Ob jects(存储驱动程序和设备对象)”)创建单一的设备对象 代表HBA,而1/0管理器通过(或者从)适当的SCSI类驱动程序把IRP发送到与那个
29 存在注册表中。最低层驱动程序也能调用 IoXxx 和/或 RtlXxx 支持例程,以获得和设置注 册表中的配置信息。更多的信息参见《既插即用、电源管理和安装设计指南》的第 4 部 分,第 2 章“注册表中的驱动程序信息”。 与 I/O 管理器类似,安全参考监视器(Security Reference Monitor)、配置管理器 (Configuration Manager)、对象管理器、过程结构、内存管理器、运行支持和内核组 件,每个都定义一组不透明的对象类型和数据结构。驱动程序只能通过调用适当的内核模 式支持例程来使用这些对象和数据结构。 如图 3.1 所示,最低层(设备)和中间层驱动程序的作者可以忽略本地过程调用(LPC)组 件。只有某些最高层的驱动程序调用由安全组件提供的支持例程。在 IRP 被送到较低层的 驱动程序之前,I/O 管理器或者文件系统驱动程序执行任何必要的进程内通信和安全访问 检查。I/O 管理器和对象管理器也在把 IRP 发送到低层驱动程序之前解析符号联接。 如图 3.1 所示,I/O 管理器为操纵由其他组件定义的某些对象和数据结构提供支持例程, 包括符号链接对象、中断对象、DPC 对象、定时器对象和内存描述符表(MDL)。这些 IoXxx 支持例程帮助实现某些标准驱动程序例程,并且映射缓冲区,这可以与驱动程序定 制的被发往较低层驱动程序的 IRP 相关。大多数驱动程序仅仅要求 IoXxx 支持例程做下列 事情中的一些: ▪ 为设备注册标准 ISR(IoConnectInterrupt),以及当设备被移走的时候注销 ISR (IoDisconnectInterrupt)。 ▪ 注册标准 DpcForIsr 例程(IoInitializeDpcRequest),并且从它的 ISR 中向驱动程 序的 DpcForlsr 例程请求一个调用(IoRequestDpc)。 ▪ 注册标准 IoTimer 例程(IoInitializeTimer),并且能够启用或禁止使每秒对 IoTimer 例程的调用(分别是 IoStartTimer 和 IoStopTimer)。 ▪ 将一个已经被与某个输入 IRP 相关的 MDL 映射的过大的缓冲区拆分成较小的映射的缓 冲区,从而使的驱动程序能在具有有限数据传输能力的设备上进行 DMA 操作。 除了文件系统驱动程序,当它们调用 IoCreateDevice 时,I/O 管理器也为驱动程序创建的 每个设备对象安装一个相关的设备队列。它也提供这样的支持例程,驱动程序调用这样的 支持例程以拥有发往它们的 StartIo 例程的 IRP。IoStartPacket 和 IoStartNextPacket 例 程根据驱动程序的需要调用内核的设备队列支持例程。 然而,驱动程序如果必要的话能调用许多 I/O 管理器调用的相同的内核支持例程。取决于 驱动程序的设计和它的设备,驱动程序能创建: ▪ 定时器对象和能明确地被排队作为 CustomTimerDpc 例程的相关 DPC 对象。例如,如果 驱动程序的设备要求可变的超时间隔或者比每秒一次更精细的间隔,驱动程序可能拥 有 CustomTimerDpc,而非 IoTimer 例程。 ▪ 一个或多个 DPC 对象和来自 ISR 明确地排队驱动程序提供的 CustomDpc 例程。例如, 一个串口驱动程序可以排队一个 CustomDpc,它可以在它的 ISR 检测到设备错误的时 候取消未决的 I/O 请求。 ▪ 设备专用线程和工作者线程在其上回调例程的定时器对象能等待驱动程序指定的时间 间隔。创建它们自己设备专用系统线程的驱动程序,诸如系统软盘驱动程序,也能有 它们的线程来等待内核定义事件、信号量,或者可能有互斥体,就向最高层驱动程序 的工作线程能回调例程那样。驱动程序能通过调用 PsCreateSystemThread 来创建设备 专用线程,并能使用 PsTerminateSystemThread 释放这样的线程。 ▪ 附加的设备队列对象。例如,SCSI 端口驱动程序(参见在线 DDK 中“Storage Drivers and Device Objects(存储驱动程序和设备对象)”) 创建单一的设备对象 代表 HBA,而 I/O 管理器通过(或者从)适当的 SCSI 类驱动程序把 IRP 发送到与那个
HBA设备对象有关的设备队列中。然而,SCSI端口驱动程序为HBA特定的SCSI总线上 的每个逻辑单元创建一个额外的设备队列对象,这个SCSI总是先由SCSI类驱动程序 声明的。SCSI端口驱动程序使用这些额外的设备队列来排序进入的IRP到逻辑单元特 定的设备队列。 因为所有的 DriverEntry和 AddDevice例程在系统线程的环境中被调用,在较高层驱动程 序已经链自己到相邻的较低层驱动程序上以后,当它初始化的时候,它也可以等待内核事 件对象。例如,类驱动程序的 AddDevice例程可以调用 IoBuildSynchronousFsdRequest使 用一个相关的事件创建IRP,并且使用 loCallDriver传递它的驱动程序分配的IRP到下层 的端口驱动程序。当位于这样的类驱动程序之下的端口驱动程序收集(或设置)设备状态 信息(类驱动程序需要这些信息以完成它的设备的初始化)的时候,这样的类驱动程序可 以通过调用 KeWaitForSingleOb ject来等待事件 运行支持( Executive Support)组件,图3.1中的内核和内存管理器组件之间,提供要求 初始化的自旋锁的特定支持例程,调用者必须为这些自选锁提供存储。包含词“互锁 ( interlocked)的任何执行体支持例程要求调用者提供的自旋锁作为参数。执行体支持组 件也为分配系统空间(存储池)内存的驱动程序和使用系统工作者线程的最高层驱动程序 (例如FSD)提供例程。 驱动程序是否使用内存管理器的例程来操纵ML部分取决于其设备的性质。当每个驱动程 序安装它的设备对象的时候,它决定它是否使用ML去访问用户缓冲区。 31.2存储系统定义的对象 使用Ⅰ0管理器的中断、DPC和定时器支持例程的驱动程序能依赖于I/0管理器为任何必 要和有关的内核定义的对象提供存储。然而,内核并不代表调用者为支持例程分配内存。 因而,任何调用 Kexxx例程的系统组件,包括任何驱动程序,必须为它使用的系统定义的 对象提供存储。例如,任何拥有标准 CustomTimerDpc例程的驱动程序为了调用操作它所需 要的定时器和DPC对象的内核支持例程,必须为这些对象提供存储 有中断服务程序(ISR)的驱动程序必须为由 IoConnectInterrupt返回的中断对象指针提 供存储。I/0管理器为驱动程序的中断对象(在SMP机器中,每个处理器一个)提供存 储,并且初始化它们。 内核实际上使用相关的中断自旋锁定义中断对象类型,并且提供 KeSynchronizeExecution,驱动程序使用由 loConnectInterrupt返回的中断对象指针来调 用它,并使用驱动程序提供 SynchCritSection例程来保证对另一个驱动程序例程和驱动程 序的ISR之间的共享数据的多处理器安全访问。 驱动程序也能提供存储、初始化、并使用执行体自旋锁,调用 KeAcquireSpinLock和 KeReleasespinLock来管理对数据的多处理器安全访问,这些数据是在驱动程序例程中间 共享的,但是不包括ISR。在 IRQ DISPATCH LEVEL上运行并共享状态的驱动程序例程能调 用 KeAcquireSpinLockAtDpcLeve和 KeReleaseSpinLock FromDpcLevel,它们比 KeAcquireSpinLock和 KeReleaseSpinLock运行的更快。当然,注意自旋锁不是对象,它 是一个不透明的、内核定义的使用内存的同步机制。标准驱动程序例程被调用的IRQL的总 述和用法参见第16章的“使用自旋锁” 驱动程序通常在它们创建的设备对象的设备扩展内为它们的系统定义的对象和自旋锁(如 果有)分配存储空间。如果驱动程序使用控制器对象,并且有 Controllercontrol例程, 它们在控制器扩展中分配存储空间,像系统“AT”盘驱动程序那样
30 HBA 设备对象有关的设备队列中。然而,SCSI 端口驱动程序为 HBA 特定的 SCSI 总线上 的每个逻辑单元创建一个额外的设备队列对象,这个 SCSI 总是先由 SCSI 类驱动程序 声明的。SCSI 端口驱动程序使用这些额外的设备队列来排序进入的 IRP 到逻辑单元特 定的设备队列。 因为所有的 DriverEntry 和 AddDevice 例程在系统线程的环境中被调用,在较高层驱动程 序已经链自己到相邻的较低层驱动程序上以后,当它初始化的时候,它也可以等待内核事 件对象。例如,类驱动程序的 AddDevice 例程可以调用 IoBuildSynchronousFsdRequest 使 用一个相关的事件创建 IRP,并且使用 IoCallDriver 传递它的驱动程序分配的 IRP 到下层 的端口驱动程序。当位于这样的类驱动程序之下的端口驱动程序收集(或设置)设备状态 信息(类驱动程序需要这些信息以完成它的设备的初始化)的时候,这样的类驱动程序可 以通过调用 KeWaitForSingleObject 来等待事件。 运行支持(Executive Support)组件,图 3.l 中的内核和内存管理器组件之间,提供要求 初始化的自旋锁的特定支持例程,调用者必须为这些自选锁提供存储。包含词“互锁” (interlocked)的任何执行体支持例程要求调用者提供的自旋锁作为参数。执行体支持组 件也为分配系统空间(存储池)内存的驱动程序和使用系统工作者线程的最高层驱动程序 (例如 FSD)提供例程。 驱动程序是否使用内存管理器的例程来操纵 MDL 部分取决于其设备的性质。当每个驱动程 序安装它的设备对象的时候,它决定它是否使用 MDL 去访问用户缓冲区。 3.1.2 存储系统定义的对象 使用 I/O 管理器的中断、DPC 和定时器支持例程的驱动程序能依赖于 I/O 管理器为任何必 要和有关的内核定义的对象提供存储。然而,内核并不代表调用者为支持例程分配内存。 因而,任何调用 KeXxx 例程的系统组件,包括任何驱动程序,必须为它使用的系统定义的 对象提供存储。例如,任何拥有标准 CustomTimerDpc 例程的驱动程序为了调用操作它所需 要的定时器和 DPC 对象的内核支持例程,必须为这些对象提供存储。 有中断服务程序(ISR)的驱动程序必须为由 IoConnectInterrupt 返回的中断对象指针提 供存储。I/O 管理器为驱动程序的中断对象(在 SMP 机器中,每个处理器一个)提供存 储,并且初始化它们。 内核实际上使用相关的中断自旋锁定义中断对象类型,并且提供 KeSynchronizeExecution,驱动程序使用由 IoConnectInterrupt 返回的中断对象指针来调 用它,并使用驱动程序提供 SynchCritSection 例程来保证对另一个驱动程序例程和驱动程 序的 ISR 之间的共享数据的多处理器安全访问。 驱动程序也能提供存储、初始化、并使用执行体自旋锁,调用 KeAcquireSpinLock 和 KeReleaseSpinLock 来管理对数据的多处理器安全访问,这些数据是在驱动程序例程中间 共享的,但是不包括 ISR。在 IRQ DISPATCH_LEVEL 上运行并共享状态的驱动程序例程能调 用 KeAcquireSpinLockAtDpcLevel 和 KeReleaseSpinLockFromDpcLevel,它们比 KeAcquireSpinLock 和 KeReleaseSpinLock 运行的更快。当然,注意自旋锁不是对象,它 是一个不透明的、内核定义的使用内存的同步机制。标准驱动程序例程被调用的 IRQL 的总 述和用法参见第 l6 章的“使用自旋锁”。 驱动程序通常在它们创建的设备对象的设备扩展内为它们的系统定义的对象和自旋锁(如 果有)分配存储空间。如果驱动程序使用控制器对象,并且有 ControllerControl 例程, 它们在控制器扩展中分配存储空间,像系统“AT”盘驱动程序那样