Nt Kernel Memory Allocation

Some important Globals concerning memory.

These globals are defined in ntos/mm/miglobal.c and set in ntos/mm/mminit.c and ntos/mm/i386/init386.c.


Global Example Value Notes

MmHighestUserAddress 0x7ffeffff
MmUserProbeAddress 0x7fff0000 One more than MmHighestUserAddress
MmSystemRangeStart 0x80000000 First 4Meg maps directly to [0,0x00400000) physical memory by a single PDE marked "Large Page".
MmNonPagedPoolStart 0x8051d000
MmPfnDatabase 0x83f9f000
MmWinStationSpaceBase 0xa3000000 Base Structure. Current MM_WINSTATION_SPACE struct always found here. This region is per session.
0xa3010000 Winstation Space Driver Images Base
0xa3c00000 Winstation Space Working Set
0xa4000000 Winstation Space Paged Pool
0xa5000000 Winstation Space Mapped Views
MmKStackPoolStart 0xa8000000 One byte above WinStation Space.
Also known as System PTE Expansion in NT5.0.
0xc0000000 Page Table base
MmSystemPteBase 0xc0200000 PTE for VA 0x80000000
MmFirstPteForPagedPool 0xc0384000 PTE for VA 0xe1000000 (MmPagedPoolStart)
MmLastPteForPagedPool 0xc0390ffc
MmSystemPtesStart[0] 0xc03e3000 (enum _MMSYSTEM_PTE_POOL_TYPE).SystemPteSpace == 0
PTE for VA 0xf8c00000 (MmNonPagedSystemStart)
MmSystemPtesEnd[0] 0xc03f94a8
MmSystemPtesStart[1] 0xc03f94b0 (enum _MMSYSTEM_PTE_POOL_TYPE).NonPagedPoolExpansion == 1
PTE for VA 0xfe52c000 (MmNonPagedPoolExpansionStart)
MmSystemPtesEnd[1] 0xc03fef7c
0xc0400000 Page table end + 1
MmPagedPoolStart 0xe1000000 Fixed Address
MmPagedPoolEnd 0xe43fffff
MmNonPagedSystemStart 0xf8c00000 The region known as "system PTE's".
MmNonPagedPoolExpansionStart 0xfe52c000
MmNonPagedPoolEnd 0xffbe0000

MmNumberOfSystemPtes 0x0000592b (MmSystemPtesEnd[0]-MmSystemPtesStart[0])/4+1
HKLM/System/.../Control/Session_Manager/Memory_Management (DWORD) System_Pages or default
MmNumberOfPhysicalPages 0x00003f6e 64M RAM
MmWinStationSpaceSize 0x05000000 Distance from MmWinStationSpaceBase to MmKStackPoolStart.

These are available in kd as follows:
kd> dd MmNumberOfSystemPtes
801565e0  0000592b 83f9f000 00003f6e 00000000

Converting Virtual Address to PTE's.

The page tables are based at 0xc0000000. 32 bits of address space must be represented by all PTE's. Each PTE represents 12 bits of address space (a 4K page) and itself consumes 2 bits (PTE = 4 bytes). So:

    32 - 12 + 2 = 22 bits
of address space is required. Therefore the top of the page table is at 0xc0400000-1.

The relationship between VA, a virtual address, and PTE, the address of the PTE for that address, is:

   VA = (( PTE - PTE_BASE )/ 4 ) * 4K
   PTE = ( VA/4K ) * 4 + PTE_BASE
It is useful to note:
   PTE_BASE = 0xc0000000
   4K = 0x1000
Because 4K is so nicely represented in hex, the only hard part for by-hand calculation is the division or multiplication by 4.

For example, the PTE for the base of the PTE table is:

   PTE = ( 0xc0000000 / 0x1000 ) * 4 + 0xc0000000
       = 0xc0000 * 4 + 0xc0000000
       = 0x300000 + 0xc0000000
       = 0xc0300000
By clever coincidence, the page of PTE's starting at this addess is the PDE - a page of PTE's pointing to other pages of PTE's. The PTE of this VA is:
   PTE = ( 0xc0300000 / 0x1000 ) * 4 + PTE_BASE
       = 0xc0300c00
This PTE contains the page frame number of the page holding the page directory. However, there must also be some PDE containing this page frame number. Since address translation will work even if each PTE/PDE references a different page frame, the PDE for this address must be the same as the PTE for this address.

The PTE for 0xc0300c00, since it is on the same page as the previously calculated PTE, is at 0xc0300c00. This PTE maps itself.

We check this, and that the page frame number in this PTE/PDE is loaded into CR3:

kd> !pte c0300c00
C0300000  - PDE at C0300C00        PTE at C0300C00
          contains 00030067      contains 00030067
        pfn 00030 --DA--UWV    pfn 00030 --DA--UWV

kd> r
eax=00000001 ebx=00725d11 ecx=8014d25c edx=000002f8 esi=000000ae edi=c1979f90
eip=80135b18 esp=801509f4 ebp=80150a04 iopl=0         nv up ei pl nz na pe nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00000202
cr0=8001003f cr2=01020004 cr3=00030000

kd>

Remarks on the PTE map.

The previous paragraph remarked that virtual address 0xc0300c00 is mapped by the PTE at the same virtual address. This is explained as the fixed point of the PTE map. Recall that the PTE map, PTE = h(VA), is linear:

    PTE = h( VA ) 
        = ( VA / PAGE_SIZE ) * PTE_SIZE + PTE_BASE
So there is a solution to x = h(x). However, this solution need not be integral, so this explanation of the fixed point is faulty.

Note, however, that this special address, PTE_f = 0xc0300c00, can be calculated, for any PTE_BASE, as the third iterate of the map h:

    PTE_f = h( h( h( X ) ) ),  for any virtual address X.
The first iterate maps an arbitrary virtual address to a PTE-aligned virtual address in the page table; the second iterate maps this address to a PDE in the page directory; and the third iterate maps this address the map's fixed point.

This is all by virtue that h is a contracting map:

    X /superset h(X) /superset h(h(X)) /superset ... /superset Y
and the displayed descending chain of address subsets must stablized, since the sets are discrete. Although abstract, this paragraph is a complete proof of the fixed point and illustrates all the conditions necessary for its existence.

For instace, for h to be contracting, the page directory must land page aligned. Hence we find that PTE_BASE must be aligned on a 4M boundary, or 0x00400000. The length of the chain before stabilization is one more than the layers of page tables. The two level page tables of the i386 implies that 3 interations of h are necessary.

As an alternative but hypothetical example, consider 256 byte pages of 64 PTE's per page, PTE's still 4 bytes. This would give a four level page table where each level uses 6 bits, and the final offset is 8 bits. ( 4*6+8=32 ). The fixed point would be calculated by taking h(h(h(h(h(X))))) for any X in the address space.

WinStation space layout.

The following comment is from ntos/mm/citrix/ctxmi.h. Only MmWinstationSpaceBase is a global and can be included in the table of significant globals.

//
// Address Map when MmWinstationSpaceBase == 0xA3000000.
//
// When the system is booted in 2GB mode, these addresses
// change.
//
// MmWinStationSpaceBase+0
//             Base structure
//             64K
//
// MmWinStationSpaceBase+0x10000
//             Driver images
//             12M-64K   (re)based drivers allocated from top down
//                       WIN32K.SYS based at 0xA3010000 always
//
// MmWinStationSpaceBase+0xC00000
//             Working Set
//             4M
//
// MmWinStationSpaceBase+0x1000000
//             Paged Pool
//             16M
//
// MmWinStationSpaceBase+0x2000000
//             Mapped Views
//             16M
//
//             Total
//             48M
//
// MmWinStationSpaceBase+0x3000000
//             KSTACK POOL
//
//             Total 416M
//
//

The WinstationSpace structures are in kernel space, but the active WinstaionSpace structure is mapped to MmWinStationSpaceBase. The first DWORD of this structure is the signature 0x0ccccccc, so this value should always appear at 0a3000000.

The MM_WINSTATIONSPACE structures are double-linked into a chain rooted at some global. Inside the structures are 20 PDE's which map up to 80M of Winstation space. Japanese has more.