## 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.