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 标志进行按位 OR 运算。

  • LowPagePriority 表示当系统的资源相当少时,映射请求可以失败。 这种情况的一个例子是网络连接并不关键,驱动程序可以处理映射失败问题。

  • NormalPagePriority 表示当系统的资源非常少时,映射请求可以失败。 这种情况的一个例子是本地文件系统请求并不关键。

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

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

  • MdlMappingNoExecute 表示要将映射的物理页面配置为不可执行内存。 从 Windows 8 开始,此标志位可以结合 MM_PAGE_PRIORITY 值进行按位 OR 运算,以指定要在其中禁用指令执行的内存。 最佳做法是,除非明确需要可执行内存,否则,为 Windows 8 和更高版本的 Windows 编写的驱动程序应始终指定不可执行内存。

返回值

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

注解

如果指定 MDL 描述的物理页面尚未映射到系统地址空间,此例程会将这些页面映射到系统地址空间。

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

进入此例程后,指定的 MDL 必须描述已锁定的物理页面。 可以使用 MmProbeAndLockPagesMmBuildMdlForNonPagedPoolIoBuildPartialMdlMmAllocatePagesForMdlEx 例程生成锁定的 MDL。

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

  • 如果 MDL 是通过调用 MmProbeAndLockPages 例程生成的,则无需显式释放系统地址空间映射。 可以调用 MmUnlockPages 例程来释放映射(如果已分配)。

  • 如果 MDL 是通过调用 MmBuildMdlForNonPagedPool 例程生成的,则 MmGetSystemAddressForMdlSafe 会重复使用现有的系统地址空间映射,而不是创建新的映射。 在这种情况下,无需进行清理(即,无需解除锁定和取消映射)。

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

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

从 Windows 7 和 Windows Server 2008 R2 开始,不必要对 MmAllocatePagesForMdlEx 创建的 MDL 显式调用 MmUnmapLockedPages。 调用 MmFreePagesFromMdl 例程可以释放系统地址空间映射(如果已分配)。

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

MmMapLockedPagesSpecifyCache 的调用中,仅当 MDL 描述的页面尚无关联的缓存类型时,才使用指定的缓存类型。 不过,几乎在所有情况下,页面都已有关联的缓存类型,并且此缓存类型已由新的映射使用。 MmAllocatePagesForMdl 分配的页面不适用此规则:无论页面的原始缓存类型是什么,该例程都会将缓存类型设置为 MmCached

每次只有一个线程可以安全地对特定的 MDL 调用 MmGetSystemAddressForMdlSafe,因为此例程假设调用方线程拥有该 MDL。 但是,可对同一 MDL 多次调用 MmGetSystemAddressForMdlSafe,调用方法是:从同一线程发出所有调用;如果从多个线程发出调用,可以显式同步调用。

如果驱动程序必须将请求拆分成较小的请求,该驱动程序可以分配更多的 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)