将直接 I/O 与 DMA 配合使用
下图演示了 I/O 管理器如何为使用直接 I/O 的 DMA 传输操作设置 IRP_MJ_READ 请求。
上图演示了驱动程序如何使用 IRP 的 MdlAddress 传输读取请求的数据。 图中的驱动程序使用基于数据包的系统或总线主 DMA,并具有带DO_DIRECT_IO的设备对象的 标志 的 ORed。
用户空间虚拟地址的一些范围表示当前线程的缓冲区,该缓冲区的内容实际上可能存储在上图) (深色着色的一些物理不连续页面上。 I/O 管理器创建 MDL 来描述此缓冲区。 MDL 是内存管理器定义的不透明数据结构,它将特定虚拟地址范围映射到一个或多个基于页面的物理地址范围。 有关详细信息,请参阅使用 MDL。
I/O 管理器为当前线程的读取请求提供服务,线程会为此传递表示缓冲区的一系列用户空间虚拟地址。
I/O 管理器或文件系统驱动程序 (FSD) 检查用户提供的缓冲区的辅助功能,并使用以前创建的 MDL 调用 MmProbeAndLockPages 。 MmProbeAndLockPages 还会填充 MDL 中相应的物理地址范围。
如上图所示,虚拟范围的 MDL 可以有多个相应的基于页面的物理地址条目,缓冲区的虚拟范围可能以 MDL 描述的第一页和最后一页开头的某个字节偏移量开始和结束。
I/O 管理器提供指向 IRP 中请求传输操作的 MDL (MdlAddress) 的指针。 在 I/O 管理器或文件系统在驱动程序完成 IRP 后调用 MmUnlockPages 之前,MDL 中所述的物理页面将保持锁定状态并分配给缓冲区。 但是,在将 IRP 发送到设备驱动程序或可能分层到设备驱动程序的任何中间驱动程序之前,此类 MDL 中的虚拟地址可能会变得不可见 (和无效的) 。
如果驱动程序使用基于数据包的系统或总线主 DMA,则其 AdapterControl 例程使用 IRP 的 MdlAddress 指针调用 MmGetMdlVirtualAddress,以获取 MDL 基于页面的条目的基虚拟地址。
然后,AdapterControl 例程使用 MmGetMdlVirtualAddress 返回的基址调用 MapTransfer,将数据从设备直接读取到物理内存中。 (有关详细信息,请参阅 适配器对象和 DMA.)
驱动程序应始终检查缓冲区长度。 请注意,I/O 管理器不会为零长度缓冲区创建 MDL。