MmGetSystemAddressForMdlSafe 函数 (wdm.h)

MmGetSystemAddressForMdlSafe 宏返回指定 MDL 描述的缓冲区的非分页系统空间虚拟地址。

语法

PVOID MmGetSystemAddressForMdlSafe(
  [in] PMDL  Mdl,
  [in] ULONG Priority
);

参数

[in] Mdl

指向要映射其相应基本虚拟地址的缓冲区的指针。

[in] Priority

指定一个 MM_PAGE_PRIORITY 值,该值指示在低可用 PTE 条件下成功的重要性。 指定 LowPagePriorityNormalPagePriorityHighPagePriority的优先级值。 从 Windows 8 开始,指定的优先级值可以使用 MdlMappingNoWriteMdlMappingNoExecute 标志进行按位 ORed。

  • LowPagePriority 指示如果系统在资源上相当低,映射请求可能会失败。 这种情况的一个示例是一个非关键网络连接,驱动程序可以处理映射失败。

  • NormalPagePriority 表示,如果系统在资源上非常低,映射请求可能会失败。 这种情况的一个示例是非关键本地文件系统请求。

  • HighPagePriority 表示,除非系统完全超出资源,否则映射请求不能失败。 这种情况的一个示例是驱动程序中的分页文件路径。

  • MdlMappingNoWrite 指示映射的物理页配置为无写入(只读)内存。 从 Windows 8 开始,此标志位可以是带 MM_PAGE_PRIORITY 值的按位 ORed,以指定禁用写入的内存。

  • MdlMappingNoExecute 指示将映射的物理页配置为无执行内存。 从 Windows 8 开始,此标志位可以是带 MM_PAGE_PRIORITY 值的按位 ORed,以指定禁用指令执行的内存。 最佳做法是,为 Windows 8 和更高版本的 Windows 编写的驱动程序应始终指定无执行内存,除非显式需要可执行内存。

返回值

MmGetSystemAddressForMdlSafe 返回映射指定 MDL 描述的物理页的基本系统空间虚拟地址。 如果页面尚未映射到系统地址空间,并且尝试映射页面失败,则返回 NULL

言论

此例程将指定的 MDL 描述的物理页映射到系统地址空间(如果它们尚未映射到系统地址空间)。

编程 I/O (PIO) 设备的驱动程序调用此例程来映射用户模式缓冲区,该缓冲区由 Irp->MdlAddress(已映射到用户模式虚拟地址范围)的 MDL 描述为系统地址空间中的范围。

在进入此例程时,指定的 MDL 必须描述锁定的物理页面。 可以使用 MmProbeAndLockPagesmmBuildMdlForNonPagedPoolIoBuildPartialMdlmmAllocatePagesForMdlEx 例程来生成锁定的 MDL。

不再需要 MmGetSystemAddressForMdlSafe 返回的系统地址空间映射时,必须释放它。 发布映射所需的步骤取决于 MDL 的生成方式。 以下是四种可能的情况:

  • 如果 MDL 是通过调用 MmProbeAndLockPages 例程生成的,则无需显式释放系统地址空间映射。 相反,如果分配了映射,则调用 MmUnlockPages 例程释放映射。

  • 如果 MDL 是通过调用 MmBuildMdlForNonPagedPool 例程生成的,MmGetSystemAddressForMdlSafe 重用现有的系统地址空间映射,而不是创建新的映射。 在这种情况下,不需要清理(也就是说,不需要解锁和取消映射)。

  • 如果 MDL 是通过调用 IoBuildPartialMdl 例程生成的,驱动程序必须调用 MmPrepareMdlForReuse 例程或 IoFreeMdl 例程来释放系统地址空间映射。

  • 如果 MDL 是通过调用 MmAllocatePagesForMdlEx 例程生成的,驱动程序必须调用 MmUnmapLockedPages 例程来释放系统地址空间映射。 如果 MmGetSystemAddressForMdlSafe 为 MDL 多次调用,则后续 MmGetSystemAddressForMdlSafe 调用仅返回第一次调用创建的映射。 MmUnmapLockedPages 的调用足以释放此映射。

从 Windows 7 和 Windows Server 2008 R2 开始,对于 mmAllocatePagesForMdlEx创建的 MDL,无需显式调用 MmUnmapLockedPages。 相反,调用 MmFreePagesFromMdl 例程会释放系统地址空间映射(如果已分配)。

若要创建新的系统地址空间映射,mmGetSystemAddressForMdlSafe 调用 mmMapLockedPagesSpecifyCache,并将 CacheType 参数设置为 mmCached。 需要除 MmCached 以外的缓存类型的驱动程序应直接调用 MmMapLockedPagesSpecifyCache,而不是直接调用 MmGetSystemAddressForMdlSafe。 有关 CacheType 参数的详细信息,请参阅 mmMapLockedPagesSpecifyCache

在调用 MmMapLockedPagesSpecifyCache时,仅当 MDL 描述的页面还没有与之关联的缓存类型时,才使用指定的缓存类型。 但是,在几乎所有情况下,页面已有关联的缓存类型,并且新映射使用此缓存类型。 此规则的例外情况是,由 MmAllocatePagesForMdl分配的页面,无论页面的原始缓存类型如何,该页面都会将缓存类型设置为 MmCached

一次只能安全调用一个线程 MmGetSystemAddressForMdlSafe 特定 MDL,因为此例程假定调用线程拥有 MDL。 但是,MmGetSystemAddressForMdlSafe 可以通过从同一线程发出所有调用来多次调用同一 MDL,或者,如果调用来自多个线程,则通过显式同步调用来调用。

如果驱动程序必须将请求拆分为较小的请求,驱动程序可以分配其他 MDL,或者驱动程序可以使用 IoBuildPartialMdl 例程。

返回的基址与 MDL 中的虚拟地址具有相同的偏移量。

Windows 98 不支持 MmGetSystemAddressForMdlSafe。 请改用 mmGetSystemAddressForMdl

由于此宏调用 MmMapLockedPagesSpecifyCache,因此使用它可能需要链接到 NtosKrnl.lib。

要求

要求 价值
最低支持的客户端 Windows 2000
标头 wdm.h
IRQL <= DISPATCH_LEVEL
DDI 符合性规则 MdlAfterReqCompletedIntIoctlA(kmdf)MdlAfterReqCompletedIoctlA(kmdf)MdlAfterReqCompletedReadA(kmdf)MdlAfterReqCompletedWriteA(kmdf)