MmAllocateContiguousNodeMemory 函数 (ntddk.h)

MmAllocateContiguousNodeMemory 例程分配一系列连续的非分页物理内存,并将其映射到系统地址空间。

语法

PVOID MmAllocateContiguousNodeMemory(
  [in]           SIZE_T           NumberOfBytes,
  [in]           PHYSICAL_ADDRESS LowestAcceptableAddress,
  [in]           PHYSICAL_ADDRESS HighestAcceptableAddress,
  [in, optional] PHYSICAL_ADDRESS BoundaryAddressMultiple,
  [in]           ULONG            Protect,
  [in]           NODE_REQUIREMENT PreferredNode
);

参数

[in] NumberOfBytes

要分配的连续内存块的大小(以字节为单位)。 有关详细信息,请参阅“备注”。

[in] LowestAcceptableAddress

调用方可以使用的最低有效物理地址。 例如,如果设备只能寻址处理器物理内存地址范围前 8 MB 以上的位置,则此设备的驱动程序应将 LowestAcceptableAddress 设置为 0x0000000000800000。

[in] HighestAcceptableAddress

调用方可以使用的最高有效物理地址。 例如,如果设备只能寻址处理器物理内存地址范围前 16 MB 中的位置,则此设备的驱动程序应将 HighestAcceptableAddress 设置为 0x0000000000FFFFFF。

[in, optional] BoundaryAddressMultiple

分配的缓冲区不得交叉的物理地址倍数。 物理地址复数必须始终为 2 的幂。 此参数是可选的,可以指定为零,以指示设备没有特殊的内存边界限制。 有关详细信息,请参阅“备注”。

[in] Protect

标记指定要用于已分配内存的保护的位。 调用方必须在 Protect 参数中设置一个 (但不能同时) 以下标志位。

标记位 含义
PAGE_READWRITE (NX) 内存分配读/写、不执行。 大多数调用方应设置此标志位。 有关详细信息,请参阅“备注”。
PAGE_EXECUTE_READWRITE 分配可执行的读/写内存。 仅当调用方需要能够在分配的内存中执行指令时,才应设置此标志位。

此外,调用方可以在 Protect 参数中设置一个 (但不能同时) 以下可选标志位。

标记位 含义
PAGE_NOCACHE 分配非缓存内存。 此标志位实际上类似于调用 MmAllocateContiguousMemorySpecifyCache,CacheType 设置为 MmNonCached
PAGE_WRITECOMBINE 分配写入组合内存。 此标志位实际上类似于调用 MmAllocateContiguousMemorySpecifyCache,CacheType 设置为 MmWriteCombined

如果未指定PAGE_NOCACHE或PAGE_WRITECOMBINE,则分配的内存将完全缓存。 在这种情况下,效果类似于调用 MmAllocateContiguousMemorySpecifyCache并将 CacheType 设置为 MmCached

[in] PreferredNode

首选节点编号。 如果多处理器系统包含 N 个节点,则节点的编号从 0 到 N-1。 如果调用方将 PreferredNode 设置为 MM_ANY_NODE_OK,则例程将选择要从哪个节点分配内存。 否则,如果无法从首选节点分配指定地址范围内的内存,则例程将返回 NULL

返回值

MmAllocateContiguousNodeMemory 返回已分配内存的基虚拟地址。 如果请求无法满足,则例程返回 NULL

注解

内核模式设备驱动程序调用此例程来分配连续的物理内存块。 调用驱动程序可以指定是否使用非执行 (NX) 内存进行分配。 在非统一内存访问 (NUMA) 多处理器系统中,调用方可以指定要从中分配内存的首选节点。 节点是共享对内存区域的快速访问的处理器集合。 在非 NUMA 多处理器或单处理器系统中, MmAllocateContiguousNodeMemory 将所有内存视为属于单个节点并从此节点分配内存。

MmAllocateContiguousNodeMemory 分配物理地址空间中连续的非分页内存块。 例程将此块映射到系统地址空间中的连续虚拟内存块,并返回此块基的虚拟地址。 例程将连续内存分配的起始地址与内存页边界对齐。

驱动程序不能访问超出请求的分配大小的内存。 例如,开发人员不应假定其驱动程序可以在请求的分配结束和下一页边界之间安全地使用内存。

由于连续物理内存通常供不应求,因此应谨慎使用,并且仅在必要时使用。 必须使用连续内存的驱动程序应在驱动程序初始化期间分配此内存,因为随着操作系统分配和释放内存,物理内存可能会随着时间的推移而碎片化。 通常,驱动程序从其 DriverEntry 例程调用 MmAllocateContiguousNodeMemory 来分配内部缓冲区以供长期使用,并在卸载驱动程序之前释放缓冲区。

当不再需要内存时,必须释放 由 MmAllocateContiguousNodeMemory 分配的内存。 调用 MmFreeContiguousMemory 例程以释放 由 MmAllocateContiguousNodeMemory 分配的内存。

MmAllocateContiguousNodeMemory 类似于 MmAllocateContiguousMemorySpecifyCacheNode 例程。 与 MmAllocateContiguousMemorySpecifyCacheNode 不同, MmAllocateContiguousNodeMemory 可用于分配无执行 (NX) 内存。 最佳做法是,驱动程序应分配 NX 内存,除非驱动程序显式要求能够在分配的内存中执行指令。 通过分配 NX 内存,驱动程序通过阻止恶意软件在此内存中执行指令来提高安全性。 由 MmAllocateContiguousMemoryMmAllocateContiguousMemorySpecifyCacheMmAllocateContiguousMemorySpecifyCacheNode 例程分配的内存始终是可执行的。

如果为 BoundaryAddressMultiple 参数指定一个非零值,则分配的内存块的物理地址范围不会跨越该值的整数倍数的地址边界。 驱动程序应将此参数设置为零,除非需要非零值来绕过硬件限制。 例如,如果设备无法跨 16 兆字节的物理边界传输数据,则驱动程序应为此参数指定0x1000000值,以确保设备看到的地址不会在 16 兆字节边界处环绕。

MmAllocateContiguousNodeMemory 分配的内存未初始化。 如果内核模式驱动程序要使其对用户模式软件 (可见,则必须先将其归零,以避免泄露) 潜在的特权内容。

要求

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

另请参阅

DriverEntry

MmAllocateContiguousMemory

MmAllocateContiguousMemorySpecifyCache

MmAllocateContiguousMemorySpecifyCacheNode

MmFreeContiguousMemory