mmAllocateMdlForIoSpace 函数 (wdm.h)

MmAllocateMdlForIoSpace 例程分配 MDL 并初始化此 MDL 以描述 I/O 地址空间中的一组物理地址范围。

语法

NTSTATUS MmAllocateMdlForIoSpace(
  [in]  PMM_PHYSICAL_ADDRESS_LIST PhysicalAddressList,
  [in]  SIZE_T                    NumberOfEntries,
  [out] PMDL                      *NewMdl
);

参数

[in] PhysicalAddressList

指向 MM_PHYSICAL_ADDRESS_LIST 结构的数组的指针,这些结构描述要包含在分配的 MDL 中的物理地址范围。

[in] NumberOfEntries

PhysicalAddressList 指向的MM_PHYSICAL_ADDRESS_LIST数组中的元素数。

[out] NewMdl

指向一个位置的指针,例程将指针写入到新分配的 MDL 的位置。

返回值

如果成功,MmAllocateMdlForIoSpace 将返回STATUS_SUCCESS。 可能的错误返回值包括以下状态代码。

返回代码 说明
STATUS_INVALID_PARAMETER_1 物理地址未与页面边界对齐;或物理地址范围不是页面大小的倍数;或物理地址范围由操作系统用于 RAM,不能用作 I/O 空间。
STATUS_INSUFFICIENT_RESOURCES 系统资源不足,无法执行请求的操作。

不要假定前面的错误返回代码列表详尽无遗。 例程可能会返回列表中未显示的错误代码。

注解

此例程接受 MM_PHYSICAL_ADDRESS_LIST 结构数组作为输入参数,这些结构描述 I/O 地址空间中的一组物理地址范围,并分配描述这些范围的 MDL。 数组中的连续物理地址范围不需要是连续的。

PhysicalAddressList 数组中的物理地址范围必须满足以下条件:

  • 每个范围的基物理地址必须与内存中的PAGE_SIZE边界对齐。

  • 每个范围的大小(以字节为单位)必须是PAGE_SIZE的整数倍数。

  • 所有物理地址范围都必须位于可用作 I/O 地址空间的内存中。 它们不能位于操作系统用于 RAM 的内存空间中。

  • 所有范围的总大小必须小于 4 GB。 具体而言,总大小不能超过 2^32 - 1 个字节。

调用方负责在不再需要分配的 MDL 时释放该 MDL。 若要释放 MDL,请调用 IoFreeMdl 例程。 有关 MDL 的详细信息,请参阅使用 MDL

由 MmAllocateMdlForIoSpace 创建的 MDL 未映射到虚拟内存,但可以提供给 MapTransferEx 等例程,以启动与 MDL 描述的物理内存范围之间或从其传输的 DMA 传输。 若要将此 MDL 映射到连续的虚拟地址范围,以便处理器可以访问它,请调用 MmMapLockedPagesSpecifyCache 例程。

只有操作系统未保留用作内存的物理地址空间范围可供驱动程序用作 I/O 地址空间。 驱动程序使用 I/O 地址空间访问内存映射的硬件资源,例如设备寄存器。 驱动程序启动时,可能会收到一个或多个物理地址范围作为转换的硬件资源。 有关详细信息,请参阅 将 Bus-Relative 地址映射到虚拟地址

在某些处理器体系结构(如 x86)中,设备可以是内存映射,也可以映射到专用于设备且与内存地址空间分开的特殊 I/O 地址空间中的端口地址。 驱动程序可以使用 MmAllocateMdlForIoSpace 仅为内存映射设备分配 MDL。

示例

下面的代码示例演示如何构造 MM_PHYSICAL_ADDRESS_LIST 结构的数组,这些结构描述要包含在分配的 MDL 中的物理地址范围。

extern ULONG64 BasePhysicalAddress;
extern SIZE_T ChunkSize;
extern SIZE_T Stride;

#define ARRAYSIZE(x)  (sizeof(x)/sizeof((x)[0]))
 
NTSTATUS Status;
PMDL Mdl;
MM_PHYSICAL_ADDRESS_LIST AddressList[3];
 
AddressList[0].PhysicalAddress.QuadPart = BasePhysicalAddress;
AddressList[0].NumberOfBytes = ChunkSize;
 
BasePhysicalAddress += Stride;
 
AddressList[1].PhysicalAddress.QuadPart = BasePhysicalAddress;
AddressList[1].NumberOfBytes = ChunkSize;
 
BasePhysicalAddress += Stride;
 
AddressList[2].PhysicalAddress.QuadPart = BasePhysicalAddress;
AddressList[2].NumberOfBytes = ChunkSize;
 
Status = MmAllocateMdlForIoSpace (AddressList, ARRAYSIZE(AddressList), &Mdl);

在此示例中,起始物理地址由 BasePhysicalAddress 变量指定。 每个物理地址范围中的字节数由 ChunkSize 变量指定。 从一个物理范围的开头到下一个物理范围的开头的字节偏移量由 Stride 变量指定。 BasePhysicalAddress 必须与内存中的页边界对齐,并且 ChunkSizeStride 必须是页面大小的倍数。

要求

要求
最低受支持的客户端 从Windows 8开始可用。
目标平台 通用
标头 wdm.h (包括 Wdm.h)
Library NtosKrnl.lib
DLL NtosKrnl.exe
IRQL <= DISPATCH_LEVEL

另请参阅

IoFreeMdl

MDL

MM_PHYSICAL_ADDRESS_LIST

MapTransferEx

MmMapLockedPagesSpecifyCache