You are currently offline, waiting for your internet to reconnect

How To Map Adapter RAM into Process Address Space

This article was previously published under Q189327
Retired KB Content Disclaimer
This article was written about products for which Microsoft no longer offers support. Therefore, this article is offered "as is" and will no longer be updated.
SUMMARY
When you map a large amount of adapter memory, you may receive one of the following symptoms:
  • Unavailability of system PTEs (NO_MORE_SYSTEM_PTES).
  • Not enough contiguous process address space.
This article explains:
  • why these problems occur
  • how to work around them
  • two ways to map adapter memory into a process address space
MORE INFORMATION

Introduction to Page Table Entries (PTE)

Every process that runs on a Windows NT system has a 4 GB virtual addressranging from 0x00000000 to 0xFFFFFFFF for its use. Of this, the upper 2 GBaddress ranging from 0x8000000 to 0xFFFFFFFF is common to all processesrunning in the system, and it is called kernel or system address space. Thelower region ranging from 0x00000000 to 0x7FFFFFFF is called user addressspace.

From the process perspective, each element of virtual address conceptuallyrefers to a byte of physical memory. It is the responsibility of theVirtual Memory Manager (VMM) in conjunction with processor memory managerunit (MMU) to translate or map each virtual address into a correspondingphysical address. The VMM performs the mapping by dividing the RAM intofixed-size page frames, creating page tables to store information aboutthese page frames, and mapping them. Each PTE represents a page frame andcontains information necessary for the VMM to locate a page.

On an x86-based system that uses a 4-KB page size, the maximum number ofPTEs required to map 2 GB of address space is 524,288 (2 GB/4 KB). On atypical system, this space is used as follows:
  • A maximum of 50,000 PTEs (approximately 195 MB address space) are reserved for general use.
  • The rest is used in mapping system cache, hyperspace, paged pool, nonpaged pool, crash dump area, and so on.
This PTE pool size is automatically determined at system startup based on the amount of physical memory in the system. This pool is squeezed in between paged pool and nonpaged pool, which also grows with the amount of physical memory in the system as well.

The system uses these PTEs to create kernel thread stacks, load devicedrivers (and their DLLs), to map system virtual address space for I/Otransfers or callers of MmMapIoSpace/MmMapLockedPages/ MmGetSystemAddressForMdl/MmAllocateNonCachedMemory, and for othermiscellaneous purposes. This system PTE pool can become heavily used andheavily fragmented. This means that your driver might not be able to getenough contiguous virtual address space from the system PTE pool at anygiven time, even though the total address space still remaining in it mightbe large enough.

It also means that if your driver uses up system PTE pool entirely, other parts of the system will degrade, even resulting in threads not being created, system stalls, and outright bug checks (because some driverscall allocate-system-memory with the MustSucceed parameter set).

You must be extremely careful when using this pool-only map. Use the portions of the adapter RAM that you really need system access to from any process context, and map only the amount that you need. Do not map the whole adapter range if you do not really need to access it all from system mode.

IMPORTANT: Unmap the memory as soon as you are finished in the right process context. Otherwise, the system will run out of PTEs, and it willbug check. You can increase the default number of PTEs-calculated based onthe total system memory-up to a maximum value by adding a number (equal tothe number of pages to be increased) to the registry at:
   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager   \Memory Management\SystemPages				
You can also monitor currently available "Free System Page Table Entries"using Performance Monitor.

NOTE: The adapter memory pages are not used for page replacement. They remain mapped into the process's address space even if the process is idle or entirely swapped out.

Following are the two most common ways to map adapter memory. The firstmethod maps the memory directly into the process's user-space, and thesecond method maps into process's system-space and optionally into user-space. Both of these methods require the physical memory to be contiguous.Because of the PTE limitation, you might not be able to map a large amountof memory in system-space. However, you might be able to map into the user-space if it is not fragmented or used up.

Section Object Method

There is a sample (MAPMEM) in the Windows NT 4.0 DDK (available throughMSDN Professional membership) that shows how to perform this mapping. Hereis an outline of the technique:

  1. Get the translated physical address of the adapter memory (HalTranslateBusAddress).
  2. Open a section handle (ZwOpenSection) to the physical memory device \Device\PhysicalMemory.
  3. Reference the object handle (ObReferenceObjectByHandle) to prevent it from being deleted.
  4. Map the memory (ZwMapViewOfSection).
The virtual address you get from the ZwMapViewOfSection is only valid inthe context of the process it is mapped. If you want to access the memoryin your driver's deferred procedure call (DPC) or interrupt service routine(ISR), which runs in an arbitrary process context, you should also map thememory in the system address space (use the next method). Unmap(ZwUnMapViewOfSection) the memory in the same process context that youmapped before it exits.

NOTE: In general, it can be dangerous to use the ZwMapViewOfSection using \Device\PhysicalMemory unless you already own the physical pages. A driver that maps pages that it does not own almost always causes memory corruption because the owner can change the page attributes, free the pages, and make other changes. Drives should map only the memory that they own. Also, it is strictly illegal to map a physical address concurrently with two different attributes (that is, cached vs noncached vs writecombined). Doing this causes processor TLB corruption and unpredictable results.

On WindowsXP, the ZwMapViewOfSection function returns STATUS_CONFLICTING_ADDRESSES error if drivers try to map the same physical address concurrently with conflicting attributes.

MmMapIoSpace Method

This method shows how to map memory in the process system address space and in the process user address space.
  1. Get the translated physical address of the adapter memory (HalTranslateBusAddress).
  2. Map the memory into nonpaged system address space as follows:
          SystemVirtualAddress = MmMapIoSpace(PhysicalAddress, SizeofMemory,         CacheEnable);					
  3. Allocate an Mdl:
          Mdl = IoAllocateMdl(SystemVirtualAddress, SizeOfMemory, FALSE, FALSE,         NULL);
  4. Build the MDL to describe the memory pages:
          MmBuildMdlForNonPagedPool(Mdl);
  5. Map the memory into the process's user-space using MmMapLockedPages.Because there is an inconsistency in the return value of this function between pre-SP4 and post-SP4 releases of Windows NT, use the following statement to make this code compatible with all versions of Windows NT:
          UserVirtualAddress = (PVOID)(((ULONG)PAGE_ALIGN(MmMapLockedPages(Mdl,         Mode))) + MmGetMdlByteOffset(Mdl));					
For additional information, click the article number below to view the article in the Microsoft Knowledge Base:
199311 INFO: MmMapLockedPages Returns Actual Virtual Address in SP4
The advantage of this method is that you get SystemVirtualAddress, whichcan be used in any process context (such as DPCs and ISR), and anUserVirtualAddress that can be used by the user-mode application in whosecontext it is mapped.

If you map into system address space, you should unmap as follows:
MmUnmapIoSpace(SystemVirtualAddress, SizeofMemory);				
If you map into user address space, you should unmap as follows only while running in the context of the process in which you mapped the memory:
MmUnmapLockedPages(UserVirtualAddress, Mdl); Finally, free the MDL by calling:IoFreeMdl(Mdl);				
REFERENCES
For more information, see the Windows NT 4.0 DDK documentation, or "Inside Windows NT" by Helen Custer (Microsoft Press 1993).
MmMapIoSpace MmMapLockedPages ZwMapViewOfSection NO_MORE_SYSTEM_PTES IoFreeMdl(Mdl);
Properties

Article ID: 189327 - Last Review: 03/07/2005 18:57:12 - Revision: 1.2

  • Microsoft Win32 Device Driver Kit for Windows NT 4.0
  • kbhowto kbkmode KB189327
Feedback