Where did all that contiguous memory come from?
A curious driver writer asks: "According to the Windows Driver Kit (WDK), the MmAllocateContiguousMemory function allocates memory from the nonpaged pool, which is currently limited to 256 MB on 32-bit systems and 128 GB on 64-bit systems. However, my driver has successfully requested 370 MB on a Windows XP or Windows Server 2003 system. How can this happen?"
This driver writer discovered an undocumented internal feature of MmAllocateContiguousMemory. (Although this function operates as described in released versions of Microsoft Windows, Microsoft doesn't guarantee that it will continue to do so. Be aware of this behavior but don't rely on it in future version of Windows.)
The MmAllocateContiguousMemory function allocates contiguous memory that is nonpaged. This is different from saying that it allocates contiguous memory from the nonpaged pool.
MmAllocateContiguousMemory first attempts to allocate memory from the nonpaged pool. If a driver requests more contiguous memory than is currently available in the nonpaged pool, MmAllocateContiguousMemory instead sometimes tries to find a consecutive run of physical pages that satisfy the driver’s request. If so, it maps the pages using system page-table entries (PTEs) and returns this mapping to the caller.
Whether MmAllocateContiguousMemory searches for physical pages depends on several constraints, which might change in the future. For example, currently it searches only if the caller is running at APC_LEVEL or lower, because the memory manager must acquire synchronization at APC_LEVEL before searching.
The number of system PTEs varies in different releases of the operating system. It can range up to 460 MB on Windows 2000 and might exceed 1 GB on Windows XP and later versions. Consequently, a driver running under Windows XP or Windows Server 2003 might be able to allocate significantly more memory than under Windows 2000, even on the same physical hardware.
Remember that pool tagging applies only to memory that is allocated from the pool; physical pages mapped through PTEs are not subject to pool tagging. If MmAllocateContiguousMemory maps physical pages through PTEs, the system does not tag the allocation and you won't be able to use Driver Verifier and other tools that monitor tagged memory allocations to help you in debugging. If MmAllocateContiguousMemory does find enough memory in the nonpaged pool, it tags the allocation with the MmCm pool tag (although the tag name, too, might change in the future), and you can use tools that track tagged pool allocations to make debugging your driver much easier.
What should you do?
- Remember that nonpaged memory is a limited resource. Request only as much as your driver requires for operations other than DMA. To allocate a buffer for DMA, call AllocateCommonBuffer instead of MmAllocateContiguousMemory.
- Pay attention to the possibility of errors in memory allocation and access during debugging. Enable the Driver Verifier to track usage of tagged memory allocations.
- Be aware that the internal operation of MmAllocateContiguousMemory is subject to change in the future. Do not assume that MmAllocateContiguousMemory will allocate more memory than is available in the nonpaged pool.