4. UMDF DMA 支持:框架、通道、传输与缓冲区管理

UMDF 的 DMA 支持并非直接操作硬件 DMA 控制器,而是通过一套抽象框架,将 DMA 操作封装为 DMA 通道对象 和 DMA 传输对象,并配合 DMA 缓冲区管理 机制,实现与 PnP 管理器的协同工作。本章深入剖析这四个核心要素。

4.1 UMDF DMA 框架概述

UMDF DMA 框架位于驱动程序与内核 DMA 子系统之间,提供安全、简化的接口。其核心设计原则是:驱动运行在用户态,DMA 操作由内核态代理执行。

关键概念: UMDF 驱动不直接调用 WDM 的 DMA 函数(如 AllocateAdapterChannel),而是通过框架提供的 IWDFDmaTarget、IWDFDmaChannel 和 IWDFDmaTransaction 接口进行交互。框架负责与 PnP 管理器协商 DMA 资源,并管理映射寄存器。
UMDF DMA 框架分层架构 用户态 (UMDF 驱动) IWDFDmaTarget / IWDFDmaChannel / IWDFDmaTransaction DMA 缓冲区分配与映射 内核态 (UMDF 框架) DMA 通道管理 / 映射寄存器管理 / 传输调度 内核 DMA 子系统 (WDM / HAL)

4.2 DMA 通道对象 (IWDFDmaChannel)

DMA 通道对象代表一个逻辑 DMA 通道,它封装了与 PnP 管理器协商的 DMA 资源。每个通道对象对应一个 DMA 适配器对象,由框架在驱动创建设备时自动创建。

属性/方法说明典型值/行为
GetDmaAdapter获取关联的 DMA 适配器对象返回 IWDFDmaTarget 接口
GetMaximumTransferLength获取单次传输最大字节数由 PnP 管理器根据系统资源决定
GetMaximumFragmentLength获取单个 Scatter/Gather 片段最大长度通常为 PAGE_SIZE 或更小
GetTransferAlignment获取传输对齐要求通常为 4 或 8 字节对齐
MapTransfer将用户态缓冲区映射为 DMA 物理地址返回 IWDFDmaTransaction
调试要点: 在 WinDbg 中使用 !umdfdma 扩展命令可以查看当前设备的所有 DMA 通道对象及其状态。注意检查 GetMaximumTransferLength 的返回值,如果小于预期,可能是 PnP 资源分配受限。

4.3 DMA 传输对象 (IWDFDmaTransaction)

DMA 传输对象代表一次具体的 DMA 数据传输操作。它管理传输的 生命周期:初始化、执行、完成、取消。驱动通过调用 IWDFDmaChannel::MapTransfer 创建传输对象。

DMA 传输对象生命周期 已创建 (Created) 已初始化 (Initialized) 执行中 (Executing) 已完成 (Completed) 已取消 (Canceled) 驱动通过 IWDFDmaTransaction::Execute 启动传输,通过 IRequestCompletionRoutine 接收完成通知

4.3.1 传输对象关键方法

  • Initialize:绑定传输对象到 DMA 通道和缓冲区,设置传输方向(读/写)。
  • Execute:启动 DMA 传输。框架会向内核提交传输请求,并返回一个 IQueueCallbackDmaCompletion 回调。
  • Cancel:取消正在进行的传输。框架会尝试中止 DMA 操作,但无法保证立即停止。
  • GetTransferInfo:获取传输状态,包括已传输字节数、错误码等。
常见陷阱: 传输对象在 Execute 返回后,驱动不能立即释放缓冲区。必须等待 IRequestCompletionRoutine 回调,确认传输完成或失败后,才能安全释放或重用缓冲区。

4.4 DMA 缓冲区管理

UMDF 的 DMA 缓冲区管理涉及 用户态虚拟地址 与 物理地址 的映射。框架提供两种缓冲区分配方式:

分配方式API特点适用场景
框架分配IWDFDmaTarget::CreateDmaBuffer自动映射到用户态,保证物理连续小数据量、固定大小缓冲区
驱动分配IWDFDmaChannel::MapTransfer使用驱动预分配的缓冲区,需手动映射大数据量、动态大小、零拷贝需求

4.4.1 缓冲区映射流程

  1. 分配缓冲区:驱动在用户态分配内存(如 VirtualAlloc 或框架 API)。
  2. 锁定缓冲区:调用 IWDFDmaChannel::MapTransfer,框架将用户态虚拟地址锁定并映射为物理地址。
  3. 获取 Scatter/Gather 列表:框架返回 IWDFDmaTransaction,驱动通过 GetTransferInfo 获取物理地址片段列表。
  4. 启动传输:驱动将 Scatter/Gather 列表传递给硬件,启动 DMA。
  5. 解除映射:传输完成后,框架自动解除映射,驱动可安全访问缓冲区。
DMA 缓冲区映射与 Scatter/Gather 流程 用户态缓冲区 虚拟地址 (非连续) 框架映射 MDL / 映射寄存器 Scatter/Gather 列表 物理地址片段数组 物理页 0x1000 物理页 0x2000 物理页 0x3000 物理页 0x4000 框架自动将非连续的用户态虚拟地址映射为连续的 Scatter/Gather 物理地址列表 驱动只需将列表传递给硬件 DMA 引擎即可

4.5 与 PnP 管理器的交互

PnP 管理器在以下关键点与 UMDF DMA 框架交互:

  • 设备启动:PnP 管理器分配 DMA 资源(如 DMA 通道号、映射寄存器数量),框架据此创建 IWDFDmaChannel。
  • 资源重新平衡:当系统资源变化时,PnP 管理器可能重新分配 DMA 资源。框架会暂停所有传输,销毁旧通道,创建新通道。
  • 设备移除:PnP 管理器通知框架释放所有 DMA 资源,框架自动取消所有未完成的传输并销毁通道对象。
调试技巧: 在资源重新平衡场景中,使用 !umdfdma -v 观察通道对象的 State 字段。如果状态长时间停留在 DmaChannelStatePendingStop,说明驱动未及时完成传输,导致 PnP 操作阻塞。

4.5.1 典型交互序列

步骤PnP 管理器UMDF 框架驱动
1发送 IRP_MN_START_DEVICE解析 DMA 资源描述符接收 IPnpCallbackHardware::OnPrepareHardware
2—创建 IWDFDmaTarget 和 IWDFDmaChannel调用 IWDFDmaTarget::CreateDmaBuffer 预分配缓冲区
3—注册 DMA 完成回调实现 IQueueCallbackDmaCompletion
4发送 IRP_MN_QUERY_STOP_DEVICE暂停所有 DMA 通道,等待传输完成停止提交新传输,等待回调
5发送 IRP_MN_STOP_DEVICE销毁 DMA 通道对象释放缓冲区,清理资源
性能优化: 对于高频 DMA 传输,建议在 OnPrepareHardware 中预分配多个 DMA 缓冲区,并使用传输对象池(IWDFDmaTransactionPool)避免运行时频繁分配/释放。