/*++

Copyright (c) 1989  Microsoft Corporation

Module Name:

    mminit.c

Abstract:

    This module contains the initialization for the memory management
    system.

Author:

    Lou Perazzoli (loup) 20-Mar-1989
    Landy Wang (landyw) 02-Jun-1997

Revision History:

--*/

#include "mi.h"

PMMPTE MmSharedUserDataPte;

extern ULONG_PTR MmSystemPtesStart[MaximumPtePoolTypes];
extern PMMPTE MiSpecialPoolFirstPte;
extern ULONG MmPagedPoolCommit;
extern ULONG MmInPageSupportMinimum;
extern PFN_NUMBER MiExpansionPoolPagesInitialCharge;
extern ULONG MmAllocationPreference;

extern PVOID BBTBuffer;
extern PFN_COUNT BBTPagesToReserve;

ULONG_PTR MmSubsectionBase;
ULONG_PTR MmSubsectionTopPage;
ULONG MmDataClusterSize;
ULONG MmCodeClusterSize;
PFN_NUMBER MmResidentAvailableAtInit;
PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
LIST_ENTRY MmLockConflictList;
LIST_ENTRY MmProtectedPteList;
KSPIN_LOCK MmProtectedPteLock;
LOGICAL MmPagedPoolMaximumDesired = FALSE;

#if defined (_MI_DEBUG_SUB)
ULONG MiTrackSubs = 0x2000; // Set to nonzero to enable subsection tracking code.
LONG MiSubsectionIndex;
PMI_SUB_TRACES MiSubsectionTraces;
#endif

#if defined (_MI_DEBUG_DIRTY)
ULONG MiTrackDirtys = 0x10000; // Set to nonzero to enable subsection tracking code.
LONG MiDirtyIndex;
PMI_DIRTY_TRACES MiDirtyTraces;
#endif

#if defined (_MI_DEBUG_DATA)
ULONG MiTrackData = 0x10000; // Set to nonzero to enable data tracking code.
LONG MiDataIndex;
PMI_DATA_TRACES MiDataTraces;
#endif

VOID
MiMapBBTMemory (
    IN PLOADER_PARAMETER_BLOCK LoaderBlock
    );

VOID
MiEnablePagingTheExecutive(
    VOID
    );

VOID
MiEnablePagingOfDriverAtInit (
    IN PMMPTE PointerPte,
    IN PMMPTE LastPte
    );

VOID
MiBuildPagedPool (
    );

VOID
MiWriteProtectSystemImage (
    IN PVOID DllBase
    );

VOID
MiInitializePfnTracing (
    VOID
    );

PFN_NUMBER
MiPagesInLoaderBlock (
    IN PLOADER_PARAMETER_BLOCK LoaderBlock,
    IN PBOOLEAN IncludeType
    );

#ifndef NO_POOL_CHECKS
VOID
MiInitializeSpecialPoolCriteria (
    IN VOID
    );
#endif

#ifdef _MI_MESSAGE_SERVER
VOID
MiInitializeMessageQueue (
    VOID
    );
#endif

static
VOID
MiMemoryLicense (
    IN PLOADER_PARAMETER_BLOCK LoaderBlock
    );

VOID
MiInitializeCacheOverrides (
    VOID
    );

//
// The thresholds can be overridden by the registry.
//

PFN_NUMBER MmLowMemoryThreshold;
PFN_NUMBER MmHighMemoryThreshold;

PKEVENT MiLowMemoryEvent;
PKEVENT MiHighMemoryEvent;

NTSTATUS
MiCreateMemoryEvent (
    IN PUNICODE_STRING EventName,
    OUT PKEVENT *Event
    );

LOGICAL
MiInitializeMemoryEvents (
    VOID
    );

#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,MmInitSystem)
#pragma alloc_text(INIT,MiMapBBTMemory)
#pragma alloc_text(INIT,MmInitializeMemoryLimits)
#pragma alloc_text(INIT,MmFreeLoaderBlock)
#pragma alloc_text(INIT,MiBuildPagedPool)
#pragma alloc_text(INIT,MiFindInitializationCode)
#pragma alloc_text(INIT,MiEnablePagingTheExecutive)
#pragma alloc_text(INIT,MiEnablePagingOfDriverAtInit)
#pragma alloc_text(INIT,MiPagesInLoaderBlock)
#pragma alloc_text(INIT,MiCreateMemoryEvent)
#pragma alloc_text(INIT,MiInitializeMemoryEvents)
#pragma alloc_text(INIT,MiInitializeCacheOverrides)
#pragma alloc_text(INIT,MiMemoryLicense)
#pragma alloc_text(PAGELK,MiFreeInitializationCode)
#endif

//
// Default is a 300 second life span for modified mapped pages -
// This can be overridden in the registry.
//

#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("INITDATA")
#endif
ULONG MmModifiedPageLifeInSeconds = 300;
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg()
#endif

LARGE_INTEGER MiModifiedPageLife;

BOOLEAN MiTimerPending = FALSE;

KEVENT MiMappedPagesTooOldEvent;

KDPC MiModifiedPageWriterTimerDpc;

KTIMER MiModifiedPageWriterTimer;

//
// The following constants are based on the number PAGES not the
// memory size.  For convenience the number of pages is calculated
// based on a 4k page size.  Hence 12mb with 4k page is 3072.
//

#define MM_SMALL_SYSTEM ((13*1024*1024) / 4096)

#define MM_MEDIUM_SYSTEM ((19*1024*1024) / 4096)

#define MM_MIN_INITIAL_PAGED_POOL ((32*1024*1024) >> PAGE_SHIFT)

#define MM_DEFAULT_IO_LOCK_LIMIT (2 * 1024 * 1024)

extern WSLE_NUMBER MmMaximumWorkingSetSize;

extern ULONG MmEnforceWriteProtection;

extern CHAR MiPteStr[];

extern LONG MiTrimInProgressCount;

#if (_MI_PAGING_LEVELS < 3)
PFN_NUMBER MmSystemPageDirectory[PD_PER_SYSTEM];
PMMPTE MmSystemPagePtes;
#endif

ULONG MmTotalSystemCodePages;

MM_SYSTEMSIZE MmSystemSize;

ULONG MmLargeSystemCache;

ULONG MmProductType;

extern ULONG MiVerifyAllDrivers;

LIST_ENTRY MmLoadedUserImageList;
PPAGE_FAULT_NOTIFY_ROUTINE MmPageFaultNotifyRoutine;

#if defined (_WIN64)
#define MM_ALLOCATION_FRAGMENT (64 * 1024 * 1024)
#else
#define MM_ALLOCATION_FRAGMENT (64 * 1024)
#endif

//
// Registry-settable.
//

SIZE_T MmAllocationFragment;


#if defined(MI_MULTINODE)

HALNUMAPAGETONODE
MiNonNumaPageToNodeColor (
    IN PFN_NUMBER PageFrameIndex
    )

/*++

Routine Description:

    Return the node color of the page.

Arguments:

    PageFrameIndex - Supplies the physical page number.

Return Value:

    Node color is always zero in non-NUMA configurations.

--*/

{
    UNREFERENCED_PARAMETER (PageFrameIndex);

    return 0;
}

//
// This node determination function pointer is initialized to return 0.
//
// Architecture-dependent initialization may repoint it to a HAL routine
// for NUMA configurations.
//

PHALNUMAPAGETONODE MmPageToNode = MiNonNumaPageToNodeColor;


VOID
MiDetermineNode (
    IN PFN_NUMBER PageFrameIndex,
    IN PMMPFN Pfn
    )

/*++

Routine Description:

    This routine is called during initial freelist population or when
    physical memory is being hot-added.  It then determines which node
    (in a multinode NUMA system) the physical memory resides in, and
    marks the PFN entry accordingly.

    N.B.  The actual page to node determination is machine dependent
    and done by a routine in the chipset driver or the HAL, called
    via the MmPageToNode function pointer.

Arguments:

    PageFrameIndex - Supplies the physical page number.

    Pfn - Supplies a pointer to the PFN database element.

Return Value:

    None.

Environment:

    None although typically this routine is called with the PFN
    database locked.

--*/

{
    ULONG Temp;

    ASSERT (Pfn == MI_PFN_ELEMENT(PageFrameIndex));

    Temp = MmPageToNode (PageFrameIndex);

    ASSERT (Temp < MAXIMUM_CCNUMA_NODES);

    Pfn->u3.e1.PageColor = Temp;
}

#endif


BOOLEAN
MmInitSystem (
    IN ULONG Phase,
    IN PLOADER_PARAMETER_BLOCK LoaderBlock
    )

/*++

Routine Description:

    This function is called during Phase 0, phase 1 and at the end
    of phase 1 ("phase 2") initialization.

    Phase 0 initializes the memory management paging functions,
    nonpaged and paged pool, the PFN database, etc.

    Phase 1 initializes the section objects, the physical memory
    object, and starts the memory management system threads.

    Phase 2 frees memory used by the OsLoader.

Arguments:

    Phase - System initialization phase.

    LoaderBlock - Supplies a pointer to the system loader block.

Return Value:

    Returns TRUE if the initialization was successful.

Environment:

    Kernel Mode Only.  System initialization.

--*/

{
    PEPROCESS Process;
    PSINGLE_LIST_ENTRY SingleListEntry;
    PFN_NUMBER NumberOfPages;
    HANDLE ThreadHandle;
    OBJECT_ATTRIBUTES ObjectAttributes;
    PMMPTE PointerPte;
    PMMPTE PointerPde;
    PMMPTE StartPde;
    PMMPTE EndPde;
    PMMPFN Pfn1;
    PFN_NUMBER i, j;
    PFN_NUMBER DeferredMdlEntries;
    PFN_NUMBER PageFrameIndex;
    PFN_NUMBER DirectoryFrameIndex;
    MMPTE TempPte;
    KIRQL OldIrql;
    PLIST_ENTRY NextEntry;
    PKLDR_DATA_TABLE_ENTRY DataTableEntry;
    ULONG MaximumSystemCacheSize;
    ULONG MaximumSystemCacheSizeTotal;
    PIMAGE_NT_HEADERS NtHeaders;
    ULONG_PTR SystemPteMultiplier;
    ULONG_PTR DefaultSystemViewSize;
    ULONG_PTR SessionEnd;
    SIZE_T SystemViewMax;
    SIZE_T HydraImageMax;
    SIZE_T HydraViewMax;
    SIZE_T HydraPoolMax;
    SIZE_T HydraSpaceUsedForSystemViews;
    BOOLEAN IncludeType[LoaderMaximum];
    LOGICAL AutosizingFragment;
    ULONG VerifierFlags;
#if DBG
    MMPTE Pointer;
#endif
#if (_MI_PAGING_LEVELS >= 3)
    LOGICAL FirstPpe;
    PMMPTE StartPpe;
#endif
#if (_MI_PAGING_LEVELS >= 4)
    LOGICAL FirstPxe;
    PMMPTE StartPxe;
#endif
#if defined(_X86_)
    PCHAR ReducedUserVaOption;
    ULONG UserVaLimit;
    ULONG ReductionInBytes;
#endif

    j = 0;
    PointerPde = NULL;

    //
    // Make sure structure alignment is okay.
    //

    if (Phase == 0) {
        MmThrottleTop = 450;
        MmThrottleBottom = 127;

        //
        // Set the highest user address, the system range start address, the
        // user probe address, and the virtual bias.
        //

#if defined(_WIN64)

        MmHighestUserAddress = MI_HIGHEST_USER_ADDRESS;
        MmUserProbeAddress = MI_USER_PROBE_ADDRESS;
        MmSystemRangeStart = MI_SYSTEM_RANGE_START;

#else

        MmHighestUserAddress = (PVOID)(KSEG0_BASE - 0x10000 - 1);
        MmUserProbeAddress = KSEG0_BASE - 0x10000;
        MmSystemRangeStart = (PVOID)KSEG0_BASE;

#endif

        MiHighestUserPte = MiGetPteAddress (MmHighestUserAddress);
        MiHighestUserPde = MiGetPdeAddress (MmHighestUserAddress);

#if (_MI_PAGING_LEVELS >= 4)
        MiHighestUserPpe = MiGetPpeAddress (MmHighestUserAddress);
        MiHighestUserPxe = MiGetPxeAddress (MmHighestUserAddress);
#endif

#if defined(_X86_) || defined(_AMD64_)

        MmBootImageSize = LoaderBlock->Extension->LoaderPagesSpanned;
        MmBootImageSize *= PAGE_SIZE;

        MmBootImageSize = MI_ROUND_TO_SIZE (MmBootImageSize,
                                            MM_VA_MAPPED_BY_PDE);

        ASSERT ((MmBootImageSize % MM_VA_MAPPED_BY_PDE) == 0);
#endif

#if defined(_X86_)
        MmVirtualBias = LoaderBlock->u.I386.VirtualBias;
#endif

        //
        // Initialize system and Hydra mapped view sizes.
        //

        DefaultSystemViewSize = MM_SYSTEM_VIEW_SIZE;
        MmSessionSize = MI_SESSION_SPACE_DEFAULT_TOTAL_SIZE;
        SessionEnd = (ULONG_PTR) MM_SESSION_SPACE_DEFAULT_END;

#define MM_MB_MAPPED_BY_PDE (MM_VA_MAPPED_BY_PDE / (1024*1024))

        //
        // A PDE of virtual space is the minimum system view size allowed.
        //

        if (MmSystemViewSize < (MM_VA_MAPPED_BY_PDE / (1024*1024))) {
            MmSystemViewSize = DefaultSystemViewSize;
        }
        else {

            //
            // The view size has been specified (in megabytes) by the registry.
            // Validate it.
            //

            if (MmVirtualBias == 0) {

                //
                // Round the system view size (in megabytes) to a PDE multiple.
                //

                MmSystemViewSize = MI_ROUND_TO_SIZE (MmSystemViewSize,
                                                     MM_MB_MAPPED_BY_PDE);

                //
                // NT64 locates system views just after systemwide paged pool,
                // so the size of the system views are not limited by session
                // space.  Arbitrarily make the maximum a PPE's worth.
                //
                //
                // NT32 shares system view VA space with session VA space due
                // to the shortage of virtual addresses.  Thus increasing the
                // system view size means potentially decreasing the maximum
                // session space size.
                //

                SystemViewMax = (MI_SESSION_SPACE_MAXIMUM_TOTAL_SIZE) / (1024*1024);

#if !defined(_WIN64)

                //
                // Ensure at least enough space is left for
                // the standard default session layout.
                //

                SystemViewMax -= (MmSessionSize / (1024*1024));
#endif

                //
                // Note a view size of -1 will be rounded to zero.  Treat -1
                // as requesting the maximum.
                //

                if ((MmSystemViewSize > SystemViewMax) ||
                    (MmSystemViewSize == 0)) {

                    MmSystemViewSize = SystemViewMax;
                }

                MmSystemViewSize *= (1024*1024);
            }
            else {
                MmSystemViewSize = DefaultSystemViewSize;
            }
        }

#if defined(_WIN64)
        HydraSpaceUsedForSystemViews = 0;
#else
        HydraSpaceUsedForSystemViews = MmSystemViewSize;
#endif
        MiSessionImageEnd = SessionEnd;

        //
        // Select reasonable Hydra image, pool and view virtual sizes.
        // A PDE of virtual space is the minimum size allowed for each type.
        //

        if (MmVirtualBias == 0) {

            if (MmSessionImageSize < MM_MB_MAPPED_BY_PDE) {
                MmSessionImageSize = MI_SESSION_DEFAULT_IMAGE_SIZE;
            }
            else {

                //
                // The Hydra image size has been specified (in megabytes)
                // by the registry.
                //
                // Round it to a PDE multiple and validate it.
                //

                MmSessionImageSize = MI_ROUND_TO_SIZE (MmSessionImageSize,
                                                        MM_MB_MAPPED_BY_PDE);

                HydraImageMax = (MI_SESSION_SPACE_MAXIMUM_TOTAL_SIZE - HydraSpaceUsedForSystemViews - (MmSessionSize - MI_SESSION_DEFAULT_IMAGE_SIZE)) / (1024*1024);

                //
                // Note a view size of -1 will be rounded to zero.
                // Treat -1 as requesting the maximum.
                //

                if ((MmSessionImageSize > HydraImageMax) ||
                    (MmSessionImageSize == 0)) {
                    MmSessionImageSize = HydraImageMax;
                }

                MmSessionImageSize *= (1024*1024);
                MmSessionSize -= MI_SESSION_DEFAULT_IMAGE_SIZE;
                MmSessionSize += MmSessionImageSize;
            }

            MiSessionImageStart = SessionEnd - MmSessionImageSize;

            //
            // The session image start and size has been established.
            //
            // Now initialize the session pool and view ranges which lie
            // virtually below it.
            //

            if (MmSessionViewSize < MM_MB_MAPPED_BY_PDE) {
                MmSessionViewSize = MI_SESSION_DEFAULT_VIEW_SIZE;
            }
            else {

                //
                // The Hydra view size has been specified (in megabytes)
                // by the registry.  Validate it.
                //
                // Round the Hydra view size to a PDE multiple.
                //

                MmSessionViewSize = MI_ROUND_TO_SIZE (MmSessionViewSize,
                                                      MM_MB_MAPPED_BY_PDE);

                HydraViewMax = (MI_SESSION_SPACE_MAXIMUM_TOTAL_SIZE - HydraSpaceUsedForSystemViews - (MmSessionSize - MI_SESSION_DEFAULT_VIEW_SIZE)) / (1024*1024);

                //
                // Note a view size of -1 will be rounded to zero.
                // Treat -1 as requesting the maximum.
                //

                if ((MmSessionViewSize > HydraViewMax) ||
                    (MmSessionViewSize == 0)) {
                    MmSessionViewSize = HydraViewMax;
                }

                MmSessionViewSize *= (1024*1024);
                MmSessionSize -= MI_SESSION_DEFAULT_VIEW_SIZE;
                MmSessionSize += MmSessionViewSize;
            }

            MiSessionViewStart = SessionEnd - MmSessionImageSize - MI_SESSION_SPACE_WS_SIZE - MI_SESSION_SPACE_STRUCT_SIZE - MmSessionViewSize;

            //
            // The session view start and size has been established.
            //
            // Now initialize the session pool start and size which lies
            // virtually just below it.
            //

            MiSessionPoolEnd = MiSessionViewStart;

            if (MmSessionPoolSize < MM_MB_MAPPED_BY_PDE) {

#if !defined(_WIN64)

                //
                // Professional and below use systemwide paged pool for session
                // allocations (this decision is made in win32k.sys).  Server
                // and above use real session pool and 16mb isn't enough to
                // play high end game applications, etc.  Since we're not
                // booted /3GB, try for an additional 16mb now.
                //

                if ((MmSessionPoolSize == 0) && (MmProductType != 0x00690057)) {

                    HydraPoolMax = MI_SESSION_SPACE_MAXIMUM_TOTAL_SIZE - HydraSpaceUsedForSystemViews - MmSessionSize;
                    if (HydraPoolMax >= 2 * MI_SESSION_DEFAULT_POOL_SIZE) {
                        MmSessionPoolSize = 2 * MI_SESSION_DEFAULT_POOL_SIZE;
                        MmSessionSize -= MI_SESSION_DEFAULT_POOL_SIZE;
                        MmSessionSize += MmSessionPoolSize;
                    }
                    else {
                        MmSessionPoolSize = MI_SESSION_DEFAULT_POOL_SIZE;
                    }
                }
                else
#endif
                MmSessionPoolSize = MI_SESSION_DEFAULT_POOL_SIZE;
            }
            else {

                //
                // The Hydra pool size has been specified (in megabytes)
                // by the registry.  Validate it.
                //
                // Round the Hydra pool size to a PDE multiple.
                //

                MmSessionPoolSize = MI_ROUND_TO_SIZE (MmSessionPoolSize,
                                                      MM_MB_MAPPED_BY_PDE);

                HydraPoolMax = (MI_SESSION_SPACE_MAXIMUM_TOTAL_SIZE - HydraSpaceUsedForSystemViews - (MmSessionSize - MI_SESSION_DEFAULT_POOL_SIZE)) / (1024*1024);

                //
                // Note a view size of -1 will be rounded to zero.
                // Treat -1 as requesting the maximum.
                //

                if ((MmSessionPoolSize > HydraPoolMax) ||
                    (MmSessionPoolSize == 0)) {
                    MmSessionPoolSize = HydraPoolMax;
                }

                MmSessionPoolSize *= (1024*1024);
                MmSessionSize -= MI_SESSION_DEFAULT_POOL_SIZE;
                MmSessionSize += MmSessionPoolSize;
            }

            MiSessionPoolStart = MiSessionPoolEnd - MmSessionPoolSize;

            MmSessionBase = (ULONG_PTR) MiSessionPoolStart;

#if defined (_WIN64)

            //
            // Session special pool immediately follows session regular pool
            // assuming the user has enabled either the verifier or special
            // pool.
            //

            if ((MmVerifyDriverBufferLength != (ULONG)-1) ||
                ((MmSpecialPoolTag != 0) && (MmSpecialPoolTag != (ULONG)-1))) {

                MmSessionSize = MI_SESSION_SPACE_MAXIMUM_TOTAL_SIZE;
                MmSessionSpecialPoolEnd = (PVOID) MiSessionPoolStart;
                MmSessionBase = MM_SESSION_SPACE_DEFAULT;
                MmSessionSpecialPoolStart = (PVOID) MmSessionBase;
            }
#endif

            ASSERT (MmSessionBase + MmSessionSize == SessionEnd);
            MiSessionSpaceEnd = SessionEnd;
            MiSessionSpacePageTables = (ULONG)(MmSessionSize / MM_VA_MAPPED_BY_PDE);
#if !defined (_WIN64)
            MiSystemViewStart = MmSessionBase - MmSystemViewSize;
#endif

        }
        else {

            //
            // When booted /3GB, no size overrides are allowed due to the
            // already severely limited virtual address space.
            // Initialize the other Hydra variables after the system cache.
            //

            MmSessionViewSize = MI_SESSION_DEFAULT_VIEW_SIZE;
            MmSessionPoolSize = MI_SESSION_DEFAULT_POOL_SIZE;
            MmSessionImageSize = MI_SESSION_DEFAULT_IMAGE_SIZE;

            MiSessionImageStart = MiSessionImageEnd - MmSessionImageSize;
        }

        //
        // Set the highest section base address.
        //
        // N.B. In 32-bit systems this address must be 2gb or less even for
        //      systems that run with 3gb enabled. Otherwise, it would not
        //      be possible to map based sections identically in all processes.
        //

        MmHighSectionBase = ((PCHAR)MmHighestUserAddress - 0x800000);

        MaximumSystemCacheSize = (MM_SYSTEM_CACHE_END - MM_SYSTEM_CACHE_START) >> PAGE_SHIFT;

#if defined(_X86_)

	    //
        // If boot.ini specified a sane number of MB that the administrator
        // wants to use for user virtual address space then use it.
        //

        UserVaLimit = 0;
        ReducedUserVaOption = strstr(LoaderBlock->LoadOptions, "USERVA");

        if (ReducedUserVaOption != NULL) {

            ReducedUserVaOption = strstr(ReducedUserVaOption,"=");

            if (ReducedUserVaOption != NULL) {

                UserVaLimit = atol(ReducedUserVaOption+1);

                UserVaLimit = MI_ROUND_TO_SIZE (UserVaLimit, ((MM_VA_MAPPED_BY_PDE) / (1024*1024)));
	        }

	        //
	        // Ignore the USERVA switch if the limit is too small.
	        //

	        if (UserVaLimit <= (2048 + 16)) {
		        UserVaLimit = 0;
	        }
        }

        if (MmVirtualBias != 0) {

            //
            // If the size of the boot image (likely due to a large registry)
            // overflows into where paged pool would normally start, then
            // move paged pool up now.  This costs virtual address space (ie:
            // performance) but more importantly, allows the system to boot.
            //

            if (MmBootImageSize > 16 * 1024 * 1024) {
                MmPagedPoolStart = (PVOID)((PCHAR)MmPagedPoolStart + (MmBootImageSize - 16 * 1024 * 1024));
                ASSERT (((ULONG_PTR)MmPagedPoolStart % MM_VA_MAPPED_BY_PDE) == 0);
            }

            //
            // The system has been biased to an alternate base address to
            // allow 3gb of user address space, set the user probe address
            // and the maximum system cache size.
            //
            // If the system has been biased to an alternate base address to
            // allow 3gb of user address space, then set the user probe address
            // and the maximum system cache size.

	        if ((UserVaLimit > 2048) && (UserVaLimit < 3072)) {

                //
                // Use any space between the maximum user virtual address
                // and the system for extra system PTEs.
                //
                // Convert input MB to bytes.
                //

                UserVaLimit -= 2048;
                UserVaLimit *= (1024*1024);

                //
                // Don't let the user specify a value which would cause us to
                // prematurely overwrite portions of the kernel & loader block.
                //

                if (UserVaLimit < MmBootImageSize) {
                    UserVaLimit = MmBootImageSize;
                }
            }
            else {
                UserVaLimit = 0x40000000;
            }

            MmHighestUserAddress = ((PCHAR)MmHighestUserAddress + UserVaLimit);
            MmSystemRangeStart = ((PCHAR)MmSystemRangeStart + UserVaLimit);
            MmUserProbeAddress += UserVaLimit;
            MiMaximumWorkingSet += UserVaLimit >> PAGE_SHIFT;

            if (UserVaLimit != 0x40000000) {
                MiUseMaximumSystemSpace = (ULONG_PTR)MmSystemRangeStart;
                MiUseMaximumSystemSpaceEnd = 0xC0000000;
            }

	        MiHighestUserPte = MiGetPteAddress (MmHighestUserAddress);
            MiHighestUserPde = MiGetPdeAddress (MmHighestUserAddress);

            //
            // Moving to 3GB means moving session space to just above
            // the system cache (and lowering the system cache max size
            // accordingly).  Here's the visual:
            //
            //                 +------------------------------------+
            //        C1000000 | System cache resides here          |
            //                 | and grows upward.                  |
            //                 |               |                    |
            //                 |               |                    |
            //                 |              \/                    |
            //                 |                                    |
            //                 +------------------------------------+
	        //		       | Session space (Hydra).		    |
            //                 +------------------------------------+
	        //		       | Systemwide global mapped views.    |
            //                 +------------------------------------+
            //                 |                                    |
            //                 |               ^                    |
            //                 |               |                    |
            //                 |               |                    |
            //                 |                                    |
            //                 | Kernel, HAL & boot loaded images   |
            //                 | grow downward from E1000000.       |
            //                 | Total size is specified by         |
            //                 | LoaderBlock->u.I386.BootImageSize. |
            //                 | Note only ntldrs after Build 2195  |
            //                 | are capable of loading the boot    |
            //                 | images in descending order from    |
            //                 | a hardcoded E1000000 on down.      |
            //        E1000000 +------------------------------------+
            //

            MaximumSystemCacheSize -= MmBootImageSize >> PAGE_SHIFT;

            MaximumSystemCacheSize -= MmSessionSize >> PAGE_SHIFT;

            MaximumSystemCacheSize -= MmSystemViewSize >> PAGE_SHIFT;

            MmSessionBase = (ULONG_PTR)(MM_SYSTEM_CACHE_START +
                                  (MaximumSystemCacheSize << PAGE_SHIFT));

            MiSystemViewStart = MmSessionBase + MmSessionSize;

            MiSessionPoolStart = MmSessionBase;
            MiSessionPoolEnd = MiSessionPoolStart + MmSessionPoolSize;
            MiSessionViewStart = MiSessionPoolEnd;

            MiSessionSpaceEnd = (ULONG_PTR)MmSessionBase + MmSessionSize;
            MiSessionSpacePageTables = MmSessionSize / MM_VA_MAPPED_BY_PDE;

            MiSessionImageEnd = MiSessionSpaceEnd;
            MiSessionImageStart = MiSessionImageEnd - MmSessionImageSize;
	}
	else if ((UserVaLimit >= 64) && (UserVaLimit < 2048)) {

	    //
	    // Convert input MB to bytes.
	    //

	    UserVaLimit *= (1024*1024);
	    ReductionInBytes = 0x80000000 - UserVaLimit;

	    MmHighestUserAddress = ((PCHAR)MmHighestUserAddress - ReductionInBytes);
	    MmSystemRangeStart = ((PCHAR)MmSystemRangeStart - ReductionInBytes);
	    MmUserProbeAddress -= ReductionInBytes;
	    MiMaximumWorkingSet -= ReductionInBytes >> PAGE_SHIFT;

	    MiUseMaximumSystemSpace = (ULONG_PTR)MmSystemRangeStart;
	    MiUseMaximumSystemSpaceEnd = (ULONG_PTR)MiUseMaximumSystemSpace + ReductionInBytes;

	    MmHighSectionBase = (PVOID)((PCHAR)MmHighSectionBase - ReductionInBytes);

	    MiHighestUserPte = MiGetPteAddress (MmHighestUserAddress);
	    MiHighestUserPde = MiGetPdeAddress (MmHighestUserAddress);
	}

#else

#if !defined (_WIN64)
        MaximumSystemCacheSize -= (MmSystemViewSize >> PAGE_SHIFT);
#endif

#endif

        //
        // Initialize some global session variables.
        //

        MmSessionSpace = (PMM_SESSION_SPACE)((ULONG_PTR)MmSessionBase + MmSessionSize - MmSessionImageSize - MI_SESSION_SPACE_STRUCT_SIZE);

        MiSessionImagePteStart = MiGetPteAddress ((PVOID) MiSessionImageStart);
        MiSessionImagePteEnd = MiGetPteAddress ((PVOID) MiSessionImageEnd);

        MiSessionBasePte = MiGetPteAddress ((PVOID)MmSessionBase);

        MiSessionSpaceWs = MiSessionViewStart + MmSessionViewSize;

        MiSessionLastPte = MiGetPteAddress ((PVOID)MiSessionSpaceEnd);

#if DBG
        //
        // A few sanity checks to ensure things are as they should be.
        //

        if ((sizeof(CONTROL_AREA) % 8) != 0) {
            DbgPrint("control area list is not a quadword sized structure\n");
        }

        if ((sizeof(SUBSECTION) % 8) != 0) {
            DbgPrint("subsection list is not a quadword sized structure\n");
        }

        //
        // Some checks to make sure prototype PTEs can be placed in
        // either paged or nonpaged (prototype PTEs for paged pool are here)
        // can be put into PTE format.
        //

        PointerPte = (PMMPTE)MmPagedPoolStart;
        Pointer.u.Long = MiProtoAddressForPte (PointerPte);
        TempPte = Pointer;
        PointerPde = MiPteToProto(&TempPte);
        if (PointerPte != PointerPde) {
            DbgPrint("unable to map start of paged pool as prototype PTE %p %p\n",
                     PointerPde,
                     PointerPte);
        }

        PointerPte =
                (PMMPTE)((ULONG_PTR)MM_NONPAGED_POOL_END & ~((1 << PTE_SHIFT) - 1));

        Pointer.u.Long = MiProtoAddressForPte (PointerPte);
        TempPte = Pointer;
        PointerPde = MiPteToProto(&TempPte);
        if (PointerPte != PointerPde) {
            DbgPrint("unable to map end of nonpaged pool as prototype PTE %p %p\n",
                     PointerPde,
                     PointerPte);
        }

        PointerPte = (PMMPTE)(((ULONG_PTR)NON_PAGED_SYSTEM_END -
                        0x37000 + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1));

        for (j = 0; j < 20; j += 1) {
            Pointer.u.Long = MiProtoAddressForPte (PointerPte);
            TempPte = Pointer;
            PointerPde = MiPteToProto(&TempPte);
            if (PointerPte != PointerPde) {
                DbgPrint("unable to map end of nonpaged pool as prototype PTE %p %p\n",
                         PointerPde,
                         PointerPte);
            }

            PointerPte += 1;
        }

        PointerPte = (PMMPTE)(((ULONG_PTR)MM_NONPAGED_POOL_END - 0x133448) & ~(ULONG_PTR)7);
        Pointer.u.Long = MiGetSubsectionAddressForPte (PointerPte);
        TempPte = Pointer;
        PointerPde = (PMMPTE)MiGetSubsectionAddress(&TempPte);
        if (PointerPte != PointerPde) {
            DbgPrint("unable to map end of nonpaged pool as section PTE %p %p\n",
                     PointerPde,
                     PointerPte);

            MiFormatPte(&TempPte);
        }

        //
        // End of sanity checks.
        //

#endif

        if (MmEnforceWriteProtection) {
            MiPteStr[0] = (CHAR)1;
        }

        InitializeListHead (&MmLoadedUserImageList);
        InitializeListHead (&MmLockConflictList);
        InitializeListHead (&MmProtectedPteList);

        KeInitializeSpinLock (&MmProtectedPteLock);

        MmCriticalSectionTimeout.QuadPart = Int32x32To64(
                                                 MmCritsectTimeoutSeconds,
                                                -10000000);

        //
        // Initialize System Address Space creation mutex.
        //

        ExInitializeFastMutex (&MmSectionCommitMutex);
        ExInitializeFastMutex (&MmSectionBasedMutex);
        ExInitializeFastMutex (&MmDynamicMemoryMutex);

        KeInitializeMutant (&MmSystemLoadLock, FALSE);

        KeInitializeEvent (&MmAvailablePagesEvent, NotificationEvent, TRUE);
        KeInitializeEvent (&MmAvailablePagesEventMedium, NotificationEvent, TRUE);
        KeInitializeEvent (&MmAvailablePagesEventHigh, NotificationEvent, TRUE);
        KeInitializeEvent (&MmMappedFileIoComplete, NotificationEvent, FALSE);

        KeInitializeEvent (&MmZeroingPageEvent, SynchronizationEvent, FALSE);
        KeInitializeEvent (&MmCollidedFlushEvent, NotificationEvent, FALSE);
        KeInitializeEvent (&MmCollidedLockEvent, NotificationEvent, FALSE);
        KeInitializeEvent (&MiMappedPagesTooOldEvent, NotificationEvent, FALSE);

        KeInitializeDpc (&MiModifiedPageWriterTimerDpc,
                         MiModifiedPageWriterTimerDispatch,
                         NULL);

        KeInitializeTimerEx (&MiModifiedPageWriterTimer, SynchronizationTimer);

        MiModifiedPageLife.QuadPart = Int32x32To64(
                                                 MmModifiedPageLifeInSeconds,
                                                -10000000);

        InitializeListHead (&MmWorkingSetExpansionHead.ListHead);

        InitializeSListHead (&MmDeadStackSListHead);

        InitializeSListHead (&MmEventCountSListHead);

        InitializeSListHead (&MmInPageSupportSListHead);

        MmZeroingPageThreadActive = FALSE;

        MiMemoryLicense (LoaderBlock);

        //
        // include all memory types ...
        //

        for (i = 0; i < LoaderMaximum; i += 1) {
            IncludeType[i] = TRUE;
        }

        //
        // ... expect these..
        //

        IncludeType[LoaderBad] = FALSE;
        IncludeType[LoaderFirmwarePermanent] = FALSE;
        IncludeType[LoaderSpecialMemory] = FALSE;
        IncludeType[LoaderBBTMemory] = FALSE;

        //
        // Compute number of pages in the system.
        //

        NumberOfPages = MiPagesInLoaderBlock (LoaderBlock, IncludeType);

#if defined (_MI_MORE_THAN_4GB_)
        Mm64BitPhysicalAddress = TRUE;
#endif

        //
        // When safebooting, don't enable special pool, the verifier or any
        // other options that track corruption regardless of registry settings.
        //

        if (strstr(LoaderBlock->LoadOptions, SAFEBOOT_LOAD_OPTION_A)) {
            MmVerifyDriverBufferLength = (ULONG)-1;
            MiVerifyAllDrivers = 0;
            MmVerifyDriverLevel = 0;
            MmDontVerifyRandomDrivers = TRUE;
            MmSpecialPoolTag = (ULONG)-1;
            MmSnapUnloads = FALSE;
            MmProtectFreedNonPagedPool = FALSE;
            MmEnforceWriteProtection = 0;
            MmTrackLockedPages = FALSE;
            MmTrackPtes = 0;

#if defined (_WIN64)
            MmSessionSpecialPoolEnd = NULL;
            MmSessionSpecialPoolStart = NULL;
#endif
            SharedUserData->SafeBootMode = TRUE;
        }
        else {
            MiTriageSystem (LoaderBlock);
        }

        SystemPteMultiplier = 0;

        if (MmNumberOfSystemPtes == 0) {
#if defined (_WIN64)

            //
            // 64-bit NT is not constrained by virtual address space.  No
            // tradeoffs between nonpaged pool, paged pool and system PTEs
            // need to be made.  So just allocate PTEs on a linear scale as
            // a function of the amount of RAM.
            //
            // For example on a Hydra NT64, 4gb of RAM gets 128gb of PTEs.
            // The page table cost is the inversion of the multiplier based
            // on the PTE_PER_PAGE.
            //

            if (ExpMultiUserTS == TRUE) {
                SystemPteMultiplier = 32;
            }
            else {
                SystemPteMultiplier = 16;
            }
            if (NumberOfPages < 0x8000) {
                SystemPteMultiplier >>= 1;
            }
#else
            if (NumberOfPages < MM_MEDIUM_SYSTEM) {
                MmNumberOfSystemPtes = MM_MINIMUM_SYSTEM_PTES;
            }
            else {
                MmNumberOfSystemPtes = MM_DEFAULT_SYSTEM_PTES;
                if (NumberOfPages > 8192) {
                    MmNumberOfSystemPtes += MmNumberOfSystemPtes;

                    //
                    // Any reasonable Hydra machine gets the maximum.
                    //

                    if (ExpMultiUserTS == TRUE) {
                        MmNumberOfSystemPtes = MM_MAXIMUM_SYSTEM_PTES;
                    }
                }
            }
#endif
        }
        else if (MmNumberOfSystemPtes == (ULONG)-1) {

            //
            // This registry setting indicates the maximum number of
            // system PTEs possible for this machine must be allocated.
            // Snap this for later reference.
            //

            MiRequestedSystemPtes = MmNumberOfSystemPtes;

#if defined (_WIN64)
            SystemPteMultiplier = 256;
#else
            MmNumberOfSystemPtes = MM_MAXIMUM_SYSTEM_PTES;
#endif
        }

        if (SystemPteMultiplier != 0) {
            if (NumberOfPages * SystemPteMultiplier > MM_MAXIMUM_SYSTEM_PTES) {
                MmNumberOfSystemPtes = MM_MAXIMUM_SYSTEM_PTES;
            }
            else {
                MmNumberOfSystemPtes = (ULONG)(NumberOfPages * SystemPteMultiplier);
            }
        }

        if (MmNumberOfSystemPtes > MM_MAXIMUM_SYSTEM_PTES)  {
            MmNumberOfSystemPtes = MM_MAXIMUM_SYSTEM_PTES;
        }

        if (MmNumberOfSystemPtes < MM_MINIMUM_SYSTEM_PTES) {
            MmNumberOfSystemPtes = MM_MINIMUM_SYSTEM_PTES;
        }

        if (MmHeapSegmentReserve == 0) {
            MmHeapSegmentReserve = 1024 * 1024;
        }

        if (MmHeapSegmentCommit == 0) {
            MmHeapSegmentCommit = PAGE_SIZE * 2;
        }

        if (MmHeapDeCommitTotalFreeThreshold == 0) {
            MmHeapDeCommitTotalFreeThreshold = 64 * 1024;
        }

        if (MmHeapDeCommitFreeBlockThreshold == 0) {
            MmHeapDeCommitFreeBlockThreshold = PAGE_SIZE;
        }

#ifndef NO_POOL_CHECKS
        MiInitializeSpecialPoolCriteria ();
#endif

        //
        // If the registry indicates drivers are in the suspect list,
        // extra system PTEs need to be allocated to support special pool
        // for their allocations.
        //

        if ((MmVerifyDriverBufferLength != (ULONG)-1) ||
            ((MmSpecialPoolTag != 0) && (MmSpecialPoolTag != (ULONG)-1))) {
            MmNumberOfSystemPtes += MM_SPECIAL_POOL_PTES;
        }

        MmNumberOfSystemPtes += BBTPagesToReserve;

#if defined(_X86_)

        //
        // The allocation preference key must be carefully managed.  This is
        // because doing every allocation top-down can caused failures if
        // an ntdll process startup allocation (like the stack trace database)
        // gets a high address which then causes a subsequent system DLL rebase
        // collision.
        //
        // This is circumvented as follows:
        //
        // 1.  For 32-bit machines, the allocation preference key is only
        //     useful when booted /3GB as only then can this key help track
        //     down apps with high virtual address bit sign extension problems.
        //     In 3GB mode, the system DLLs are based just below 2GB so ntdll
        //     would have to allocate more than 1GB of VA space before this
        //     becomes a problem.  So really the problem can only occur for
        //     machines in 2GB mode and since the key doesn't help these
        //     machines anyway, just turn it off in these cases.
        //
        // 2.  For 64-bit machines, there is plenty of VA space above the
        //     addresses system DLLs are based at so it is a non-issue.
        //     EXCEPT for wow64 binaries which run in sandboxed 2GB address
        //     spaces.  Explicit checks are made to detect a wow64 process in
        //     the Mm APIs which check this key and the key is ignored in
        //     this case as it doesn't provide any sign extension help and
        //     therefore we don't allow it to burn up any valuable VA space
	//     which could cause a collision.
	//

        if (MmVirtualBias == 0) {
            MmAllocationPreference = 0;
        }
#endif

        if (MmAllocationPreference != 0) {
            MmAllocationPreference = MEM_TOP_DOWN;
        }

        ExInitializeResourceLite (&MmSystemWsLock);

        MiInitializeDriverVerifierList (LoaderBlock);

        //
        // Set the initial commit page limit high enough so initial pool
        // allocations (which happen in the machine dependent init) can
        // succeed.
        //

        MmTotalCommitLimit = _2gb / PAGE_SIZE;
        MmTotalCommitLimitMaximum = MmTotalCommitLimit;

        //
        // Pick a reasonable size for the default prototype PTE allocation
        // chunk size.  Make sure it's always a PAGE_SIZE multiple.  The
        // registry entry is treated as the number of 1K chunks.
        //

        if (MmAllocationFragment == 0) {
            AutosizingFragment = TRUE;
            MmAllocationFragment = MM_ALLOCATION_FRAGMENT;
#if !defined (_WIN64)
            if (NumberOfPages < 64 * 1024) {
                MmAllocationFragment = MM_ALLOCATION_FRAGMENT / 4;
            }
            else if (NumberOfPages < 256 * 1024) {
                MmAllocationFragment = MM_ALLOCATION_FRAGMENT / 2;
            }
#endif
        }
	else {

	    //
            // Convert the registry entry from 1K chunks into bytes.
            // Then round it to a PAGE_SIZE multiple.  Finally bound it
            // reasonably.
            //

            AutosizingFragment = FALSE;
            MmAllocationFragment *= 1024;
            MmAllocationFragment = ROUND_TO_PAGES (MmAllocationFragment);

            if (MmAllocationFragment > MM_ALLOCATION_FRAGMENT) {
                MmAllocationFragment = MM_ALLOCATION_FRAGMENT;
            }
            else if (MmAllocationFragment < PAGE_SIZE) {
                MmAllocationFragment = PAGE_SIZE;
            }
        }

        MiInitializeIoTrackers ();

        MiInitializeCacheOverrides ();

        //
        // Initialize the machine dependent portion of the hardware.
        //

        MiInitMachineDependent (LoaderBlock);

        MmPhysicalMemoryBlock = MmInitializeMemoryLimits (LoaderBlock,
                                                          IncludeType,
                                                          NULL);

        if (MmPhysicalMemoryBlock == NULL) {
            KeBugCheckEx (INSTALL_MORE_MEMORY,
                          MmNumberOfPhysicalPages,
                          MmLowestPhysicalPage,
                          MmHighestPhysicalPage,
                          0x100);
        }

#if defined(_X86_)
        MiReportPhysicalMemory ();
#endif

#if defined (_MI_MORE_THAN_4GB_)
        if (MiNoLowMemory != 0) {
            MiRemoveLowPages (0);
        }
#endif

        //
        // Initialize listhead, spinlock and semaphore for
        // segment dereferencing thread.
        //

        KeInitializeSpinLock (&MmDereferenceSegmentHeader.Lock);
        InitializeListHead (&MmDereferenceSegmentHeader.ListHead);
        KeInitializeSemaphore (&MmDereferenceSegmentHeader.Semaphore, 0, MAXLONG);

        InitializeListHead (&MmUnusedSegmentList);
        InitializeListHead (&MmUnusedSubsectionList);
        KeInitializeEvent (&MmUnusedSegmentCleanup, NotificationEvent, FALSE);


        MiInitializeCommitment ();

        MiInitializePfnTracing ();

#if defined(_X86_)

        //
        // Virtual bias indicates the offset that needs to be added to
        // 0x80000000 to get to the start of the loaded images.  Update it
        // now to indicate the offset to MmSessionBase as that is the lowest
        // system address that process creation needs to make sure to duplicate.
        //
        // This is not done until after machine dependent initialization runs
        // as that initialization relies on the original meaning of VirtualBias.
	//
	// Note if the system is booted with both /3GB & /USERVA, then system
        // PTEs will be allocated below virtual 3GB and that will end up being
        // the lowest system address the process creation needs to duplicate.
        //

        if (MmVirtualBias != 0) {
            MmVirtualBias = (ULONG_PTR)MmSessionBase - CODE_START;
        }
#endif

        if (MmMirroring & MM_MIRRORING_ENABLED) {

#if defined (_WIN64)

            //
            // All page frame numbers must fit in 32 bits because the bitmap
            // package is currently 32-bit.
            //
            // The bitmaps are deliberately not initialized as each mirroring
            // must reinitialize them anyway.
            //

            if (MmHighestPossiblePhysicalPage + 1 < _4gb) {
#endif

                MiCreateBitMap (&MiMirrorBitMap,
                                MmHighestPossiblePhysicalPage + 1,
                                NonPagedPool);

                if (MiMirrorBitMap != NULL) {
                    MiCreateBitMap (&MiMirrorBitMap2,
                                    MmHighestPossiblePhysicalPage + 1,
                                    NonPagedPool);

                    if (MiMirrorBitMap2 == NULL) {
                        MiRemoveBitMap (&MiMirrorBitMap);
                    }
                }
#if defined (_WIN64)
            }
#endif
        }

#if !defined (_WIN64)
        if ((AutosizingFragment == TRUE) &&
            (NumberOfPages >= 256 * 1024)) {

            //
            // This is a system with at least 1GB of RAM.  Presumably it
            // will be used to cache many files.  Maybe we should factor in
            // pool size here and adjust it accordingly.
            //

            MmAllocationFragment;
        }
#endif

        MiReloadBootLoadedDrivers (LoaderBlock);

#if defined (_MI_MORE_THAN_4GB_)
        if (MiNoLowMemory != 0) {
            MiRemoveLowPages (1);
        }
#endif
        MiInitializeVerifyingComponents (LoaderBlock);

        //
        // Setup the system size as small, medium, or large depending
        // on memory available.
        //
        // For internal MM tuning, the following applies
        //
        // 12Mb  is small
        // 12-19 is medium
        // > 19 is large
        //
        //
        // For all other external tuning,
        // < 19 is small
        // 19 - 31 is medium for workstation
        // 19 - 63 is medium for server
        // >= 32 is large for workstation
        // >= 64 is large for server
        //

        if (MmNumberOfPhysicalPages <= MM_SMALL_SYSTEM) {
            MmSystemSize = MmSmallSystem;
            MmMaximumDeadKernelStacks = 0;
            MmModifiedPageMinimum = 40;
            MmModifiedPageMaximum = 100;
            MmDataClusterSize = 0;
            MmCodeClusterSize = 1;
            MmReadClusterSize = 2;
            MmInPageSupportMinimum = 2;
        }
        else if (MmNumberOfPhysicalPages <= MM_MEDIUM_SYSTEM) {
            MmSystemSize = MmSmallSystem;
            MmMaximumDeadKernelStacks = 2;
            MmModifiedPageMinimum = 80;
            MmModifiedPageMaximum = 150;
            MmSystemCacheWsMinimum += 100;
            MmSystemCacheWsMaximum += 150;
            MmDataClusterSize = 1;
            MmCodeClusterSize = 2;
            MmReadClusterSize = 4;
            MmInPageSupportMinimum = 3;
        }
        else {
            MmSystemSize = MmMediumSystem;
            MmMaximumDeadKernelStacks = 5;
            MmModifiedPageMinimum = 150;
            MmModifiedPageMaximum = 300;
            MmSystemCacheWsMinimum += 400;
            MmSystemCacheWsMaximum += 800;
            MmDataClusterSize = 3;
            MmCodeClusterSize = 7;
            MmReadClusterSize = 7;
            MmInPageSupportMinimum = 4;
        }

        if (MmNumberOfPhysicalPages < ((24*1024*1024)/PAGE_SIZE)) {
            MmSystemCacheWsMinimum = 32;
        }

        if (MmNumberOfPhysicalPages >= ((32*1024*1024)/PAGE_SIZE)) {

            //
            // If we are on a workstation, 32Mb and above are considered
            // large systems.
            //

            if (MmProductType == 0x00690057) {
                MmSystemSize = MmLargeSystem;

            }
            else {

                //
                // For servers, 64Mb and greater is a large system
                //

                if (MmNumberOfPhysicalPages >= ((64*1024*1024)/PAGE_SIZE)) {
                    MmSystemSize = MmLargeSystem;
                }
            }
        }

        if (MmNumberOfPhysicalPages > ((33*1024*1024)/PAGE_SIZE)) {
            MmModifiedPageMinimum = 400;
            MmModifiedPageMaximum = 800;
            MmSystemCacheWsMinimum += 500;
            MmSystemCacheWsMaximum += 900;
            MmInPageSupportMinimum += 4;
        }
        if (MmNumberOfPhysicalPages > ((220*1024*1024)/PAGE_SIZE)) {  // bump max cache size a bit more
            if ( (LONG)MmSystemCacheWsMinimum < (LONG)((24*1024*1024) >> PAGE_SHIFT)  &&
                 (LONG)MmSystemCacheWsMaximum < (LONG)((24*1024*1024) >> PAGE_SHIFT)){
                MmSystemCacheWsMaximum =  ((24*1024*1024) >> PAGE_SHIFT);
            }
            ASSERT ((LONG)MmSystemCacheWsMaximum > (LONG)MmSystemCacheWsMinimum);
        } 
        else if (MmNumberOfPhysicalPages > ((110*1024*1024)/PAGE_SIZE)) {  // bump max cache size a bit
            if ( (LONG)MmSystemCacheWsMinimum < (LONG)((16*1024*1024) >> PAGE_SHIFT)  &&
                 (LONG)MmSystemCacheWsMaximum < (LONG)((16*1024*1024) >> PAGE_SHIFT)){
                MmSystemCacheWsMaximum =  ((16*1024*1024) >> PAGE_SHIFT);
            }
            ASSERT ((LONG)MmSystemCacheWsMaximum > (LONG)MmSystemCacheWsMinimum);
        }

        if (NT_SUCCESS (MmIsVerifierEnabled (&VerifierFlags))) {

            //
            // The verifier is enabled so don't defer any MDL unlocks because
            // without state, debugging driver bugs in this area is very
            // difficult.
            //

            DeferredMdlEntries = 0;
        }
        else if (MmNumberOfPhysicalPages > ((255*1024*1024)/PAGE_SIZE)) {
            DeferredMdlEntries = 32;
        }
        else if (MmNumberOfPhysicalPages > ((127*1024*1024)/PAGE_SIZE)) {
            DeferredMdlEntries = 8;
        }
        else {
            DeferredMdlEntries = 4;
        }

#if defined(MI_MULTINODE)
        for (i = 0; i < KeNumberNodes; i += 1) {

            InitializeSListHead (&KeNodeBlock[i]->PfnDereferenceSListHead);
            KeNodeBlock[i]->PfnDeferredList = NULL;

            for (j = 0; j < DeferredMdlEntries; j += 1) {

                SingleListEntry = ExAllocatePoolWithTag (NonPagedPool,
                                             sizeof(MI_PFN_DEREFERENCE_CHUNK),
                                             'mDmM');
        
                if (SingleListEntry != NULL) {
                    InterlockedPushEntrySList (&KeNodeBlock[i]->PfnDereferenceSListHead,
                                               SingleListEntry);
                }
            }
        }
#else
        InitializeSListHead (&MmPfnDereferenceSListHead);

        for (j = 0; j < DeferredMdlEntries; j += 1) {
            SingleListEntry = ExAllocatePoolWithTag (NonPagedPool,
                                             sizeof(MI_PFN_DEREFERENCE_CHUNK),
                                             'mDmM');
        
            if (SingleListEntry != NULL) {
                InterlockedPushEntrySList (&MmPfnDereferenceSListHead,
                                           SingleListEntry);
            }
        }
#endif
        
        ASSERT (SharedUserData->NumberOfPhysicalPages == 0);

        SharedUserData->NumberOfPhysicalPages = (ULONG) MmNumberOfPhysicalPages;

        //
        // Determine if we are on an AS system (Winnt is not AS).
        //

        if (MmProductType == 0x00690057) {
            SharedUserData->NtProductType = NtProductWinNt;
            MmProductType = 0;
            MmThrottleTop = 250;
            MmThrottleBottom = 30;

        }
        else {
            if (MmProductType == 0x0061004c) {
                SharedUserData->NtProductType = NtProductLanManNt;
            }
            else {
                SharedUserData->NtProductType = NtProductServer;
            }

            MmProductType = 1;
            MmThrottleTop = 450;
            MmThrottleBottom = 80;
            MmMinimumFreePages = 81;
            MmInPageSupportMinimum += 8;
        }

        MiAdjustWorkingSetManagerParameters ((LOGICAL)(MmProductType == 0 ? TRUE : FALSE));

        //
        // Set the ResidentAvailablePages to the number of available
        // pages minus the fluid value.
        //

        MmResidentAvailablePages = MmAvailablePages - MM_FLUID_PHYSICAL_PAGES;

        //
        // Subtract off the size of future nonpaged pool expansion
        // so that nonpaged pool will always be able to expand regardless of
        // prior system load activity.
        //

        MmResidentAvailablePages -= MiExpansionPoolPagesInitialCharge;

        //
        // Subtract off the size of the system cache working set.
        //

        MmResidentAvailablePages -= MmSystemCacheWsMinimum;
        MmResidentAvailableAtInit = MmResidentAvailablePages;

        if (MmResidentAvailablePages < 0) {
#if DBG
            DbgPrint("system cache working set too big\n");
#endif
            return FALSE;
        }

        //
        // Initialize spin lock for allowing working set expansion.
        //

        KeInitializeSpinLock (&MmExpansionLock);

        ExInitializeFastMutex (&MmPageFileCreationLock);

        //
        // Initialize resource for extending sections.
        //

        ExInitializeResourceLite (&MmSectionExtendResource);
        ExInitializeResourceLite (&MmSectionExtendSetResource);

        //
        // Build the system cache structures.
        //

        StartPde = MiGetPdeAddress (MmSystemCacheWorkingSetList);
        PointerPte = MiGetPteAddress (MmSystemCacheWorkingSetList);

#if (_MI_PAGING_LEVELS >= 3)

        TempPte = ValidKernelPte;

#if (_MI_PAGING_LEVELS >= 4)
        StartPxe = MiGetPdeAddress(StartPde);

        if (StartPxe->u.Hard.Valid == 0) {

            //
            // Map in a page directory parent page for the system cache working
            // set.  Note that we only populate one page table for this.
            //

            DirectoryFrameIndex = MiRemoveAnyPage(
                MI_GET_PAGE_COLOR_FROM_PTE (StartPxe));
            TempPte.u.Hard.PageFrameNumber = DirectoryFrameIndex;
            *StartPxe = TempPte;

            MiInitializePfn (DirectoryFrameIndex, StartPxe, 1);

            MiFillMemoryPte (MiGetVirtualAddressMappedByPte(StartPxe),
                             PAGE_SIZE,
                             ZeroKernelPte.u.Long);
        }
#endif

        StartPpe = MiGetPteAddress(StartPde);

        if (StartPpe->u.Hard.Valid == 0) {

            //
            // Map in a page directory page for the system cache working set.
            // Note that we only populate one page table for this.
            //

            DirectoryFrameIndex = MiRemoveAnyPage(
                MI_GET_PAGE_COLOR_FROM_PTE (StartPpe));
            TempPte.u.Hard.PageFrameNumber = DirectoryFrameIndex;
            *StartPpe = TempPte;

            MiInitializePfn (DirectoryFrameIndex, StartPpe, 1);

            MiFillMemoryPte (MiGetVirtualAddressMappedByPte(StartPpe),
                             PAGE_SIZE,
                             ZeroKernelPte.u.Long);
        }

#if (_MI_PAGING_LEVELS >= 4)

        //
        // The shared user data is already initialized and it shares the
        // page table page with the system cache working set list.
        //

        ASSERT (StartPde->u.Hard.Valid == 1);
#else

        //
        // Map in a page table page.
        //

        ASSERT (StartPde->u.Hard.Valid == 0);

        PageFrameIndex = MiRemoveAnyPage(
                                MI_GET_PAGE_COLOR_FROM_PTE (StartPde));
        TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
        MI_WRITE_VALID_PTE (StartPde, TempPte);

        MiInitializePfn (PageFrameIndex, StartPde, 1);

        MiFillMemoryPte (MiGetVirtualAddressMappedByPte (StartPde),
                         PAGE_SIZE,
                         ZeroKernelPte.u.Long);
#endif

        StartPpe = MiGetPpeAddress(MmSystemCacheStart);
        StartPde = MiGetPdeAddress(MmSystemCacheStart);
        PointerPte = MiGetVirtualAddressMappedByPte (StartPde);

#else
#if !defined(_X86PAE_)
        ASSERT ((StartPde + 1) == MiGetPdeAddress (MmSystemCacheStart));
#endif
#endif

        MaximumSystemCacheSizeTotal = MaximumSystemCacheSize;

#if defined(_X86_)
        MaximumSystemCacheSizeTotal += MiMaximumSystemCacheSizeExtra;
#endif

        //
        // Size the system cache based on the amount of physical memory.
        //

        i = (MmNumberOfPhysicalPages + 65) / 1024;

        if (i >= 4) {

            //
            // System has at least 4032 pages.  Make the system
            // cache 128mb + 64mb for each additional 1024 pages.
            //

            MmSizeOfSystemCacheInPages = (PFN_COUNT)(
                            ((128*1024*1024) >> PAGE_SHIFT) +
                            ((i - 4) * ((64*1024*1024) >> PAGE_SHIFT)));
            if (MmSizeOfSystemCacheInPages > MaximumSystemCacheSizeTotal) {
                MmSizeOfSystemCacheInPages = MaximumSystemCacheSizeTotal;
            }
        }

        MmSystemCacheEnd = (PVOID)(((PCHAR)MmSystemCacheStart +
                    MmSizeOfSystemCacheInPages * PAGE_SIZE) - 1);

#if defined(_X86_)
        if (MmSizeOfSystemCacheInPages > MaximumSystemCacheSize) {
            ASSERT (MiMaximumSystemCacheSizeExtra != 0);
            MmSystemCacheEnd = (PVOID)(((PCHAR)MmSystemCacheStart +
                        MaximumSystemCacheSize * PAGE_SIZE) - 1);

            MiSystemCacheStartExtra = (PVOID)MiExtraResourceStart;
            MiSystemCacheEndExtra = (PVOID)(((PCHAR)MiSystemCacheStartExtra +
                        (MmSizeOfSystemCacheInPages - MaximumSystemCacheSize) * PAGE_SIZE) - 1);
        }
        else {
            MiSystemCacheStartExtra = MmSystemCacheStart;
            MiSystemCacheEndExtra = MmSystemCacheEnd;
        }
#endif

        EndPde = MiGetPdeAddress(MmSystemCacheEnd);

        TempPte = ValidKernelPte;

#if (_MI_PAGING_LEVELS >= 4)
        StartPxe = MiGetPxeAddress(MmSystemCacheStart);
        if (StartPxe->u.Hard.Valid == 0) {
            FirstPxe = TRUE;
            FirstPpe = TRUE;
        }
        else {
            FirstPxe = FALSE;
            FirstPpe = (StartPpe->u.Hard.Valid == 0) ? TRUE : FALSE;
        }
#elif (_MI_PAGING_LEVELS >= 3)
        FirstPpe = (StartPpe->u.Hard.Valid == 0) ? TRUE : FALSE;
#else
        DirectoryFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (MiGetPteAddress(PDE_BASE));
#endif

        LOCK_PFN (OldIrql);
        while (StartPde <= EndPde) {

#if (_MI_PAGING_LEVELS >= 4)
            if (FirstPxe == TRUE || MiIsPteOnPpeBoundary(StartPde)) {
                FirstPxe = FALSE;
                StartPxe = MiGetPdeAddress(StartPde);

                //
                // Map in a page directory page.
                //

                DirectoryFrameIndex = MiRemoveAnyPage(
                                        MI_GET_PAGE_COLOR_FROM_PTE (StartPxe));
                TempPte.u.Hard.PageFrameNumber = DirectoryFrameIndex;
                MI_WRITE_VALID_PTE (StartPxe, TempPte);

                MiInitializePfn (DirectoryFrameIndex,
                                 StartPxe,
                                 1);

                MiFillMemoryPte (MiGetVirtualAddressMappedByPte(StartPxe),
                                 PAGE_SIZE,
                                 ZeroKernelPte.u.Long);
            }
#endif

#if (_MI_PAGING_LEVELS >= 3)
            if (FirstPpe == TRUE || MiIsPteOnPdeBoundary(StartPde)) {
                FirstPpe = FALSE;
                StartPpe = MiGetPteAddress(StartPde);

                //
                // Map in a page directory page.
                //

                DirectoryFrameIndex = MiRemoveAnyPage(
                                        MI_GET_PAGE_COLOR_FROM_PTE (StartPpe));
                TempPte.u.Hard.PageFrameNumber = DirectoryFrameIndex;
                MI_WRITE_VALID_PTE (StartPpe, TempPte);

                MiInitializePfn (DirectoryFrameIndex,
                                 StartPpe,
                                 1);

                MiFillMemoryPte (MiGetVirtualAddressMappedByPte(StartPpe),
                                 PAGE_SIZE,
                                 ZeroKernelPte.u.Long);
            }
#endif

            ASSERT (StartPde->u.Hard.Valid == 0);

            //
            // Map in a page table page.
            //

            PageFrameIndex = MiRemoveAnyPage(
                                    MI_GET_PAGE_COLOR_FROM_PTE (StartPde));
            TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
            MI_WRITE_VALID_PTE (StartPde, TempPte);

            MiInitializePfn (PageFrameIndex, StartPde, 1);

            MiFillMemoryPte (MiGetVirtualAddressMappedByPte(StartPde),
                             PAGE_SIZE,
                             ZeroKernelPte.u.Long);

            StartPde += 1;
        }

        UNLOCK_PFN (OldIrql);

        //
        // Initialize the system cache.  Only set the large system cache if
        // we have a large amount of physical memory.
        //

        if (MmLargeSystemCache != 0 && MmNumberOfPhysicalPages > 0x7FF0) {
            if ((MmAvailablePages >
                    MmSystemCacheWsMaximum + ((64*1024*1024) >> PAGE_SHIFT))) {
                MmSystemCacheWsMaximum =
                            MmAvailablePages - ((32*1024*1024) >> PAGE_SHIFT);
                ASSERT ((LONG)MmSystemCacheWsMaximum > (LONG)MmSystemCacheWsMinimum);
            }
        }

        if (MmSystemCacheWsMaximum > (MM_MAXIMUM_WORKING_SET - 5)) {
            MmSystemCacheWsMaximum = MM_MAXIMUM_WORKING_SET - 5;
        }

        if (MmSystemCacheWsMaximum > MmSizeOfSystemCacheInPages) {
            MmSystemCacheWsMaximum = MmSizeOfSystemCacheInPages;
            if ((MmSystemCacheWsMinimum + 500) > MmSystemCacheWsMaximum) {
                MmSystemCacheWsMinimum = MmSystemCacheWsMaximum - 500;
            }
        }

        MiInitializeSystemCache ((ULONG)MmSystemCacheWsMinimum,
                                 (ULONG)MmSystemCacheWsMaximum);

        MmAttemptForCantExtend.Segment = NULL;
        MmAttemptForCantExtend.RequestedExpansionSize = 1;
        MmAttemptForCantExtend.ActualExpansion = 0;
        MmAttemptForCantExtend.InProgress = FALSE;
        MmAttemptForCantExtend.PageFileNumber = MI_EXTEND_ANY_PAGEFILE;

        KeInitializeEvent (&MmAttemptForCantExtend.Event,
                           NotificationEvent,
                           FALSE);

        //
        // Now that we have booted far enough, replace the temporary
        // commit limits with real ones: set the initial commit page
        // limit to the number of available pages.  This value is
        // updated as paging files are created.
        //

        MmTotalCommitLimit = MmAvailablePages;

        if (MmTotalCommitLimit > 1024) {
            MmTotalCommitLimit -= 1024;
        }

        MmTotalCommitLimitMaximum = MmTotalCommitLimit;

        //
        // Set maximum working set size to 512 pages less than the
        // total available memory.
        //

        MmMaximumWorkingSetSize = (WSLE_NUMBER)(MmAvailablePages - 512);

        if (MmMaximumWorkingSetSize > (MM_MAXIMUM_WORKING_SET - 5)) {
            MmMaximumWorkingSetSize = MM_MAXIMUM_WORKING_SET - 5;
        }

        //
        // Create the modified page writer event.
        //

        KeInitializeEvent (&MmModifiedPageWriterEvent, NotificationEvent, FALSE);

        //
        // Build paged pool.
        //

        MiBuildPagedPool ();

        //
        // Initialize the loaded module list.  This cannot be done until
        // paged pool has been built.
        //

        if (MiInitializeLoadedModuleList (LoaderBlock) == FALSE) {
#if DBG
            DbgPrint("Loaded module list initialization failed\n");
#endif
            return FALSE;
        }

        //
        // Initialize the unused segment threshold.  Attempt to keep pool usage
        // below this percentage (by trimming the cache) if pool requests
        // can fail.
        //

        if (MmConsumedPoolPercentage == 0) {
            MmConsumedPoolPercentage = 80;
        }
        else if (MmConsumedPoolPercentage < 5) {
            MmConsumedPoolPercentage = 5;
        }
        else if (MmConsumedPoolPercentage > 100) {
            MmConsumedPoolPercentage = 100;
        }
    
        //
        // Add more system PTEs if this is a large memory system.
        // Note that 64 bit systems can determine the right value at the
        // beginning since there is no virtual address space crunch.
        //

#if !defined (_WIN64)
        if (MmNumberOfPhysicalPages > ((127*1024*1024) >> PAGE_SHIFT)) {

            PMMPTE StartingPte;

            PointerPde = MiGetPdeAddress ((PCHAR)MmPagedPoolEnd + 1);
            StartingPte = MiGetPteAddress ((PCHAR)MmPagedPoolEnd + 1);
            j = 0;

            TempPte = ValidKernelPde;
            LOCK_PFN (OldIrql);
            while (PointerPde->u.Hard.Valid == 0) {

                MiChargeCommitmentCantExpand (1, TRUE);
                MM_TRACK_COMMIT (MM_DBG_COMMIT_EXTRA_SYSTEM_PTES, 1);

                PageFrameIndex = MiRemoveZeroPage (
                                    MI_GET_PAGE_COLOR_FROM_PTE (PointerPde));
                TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
                MI_WRITE_VALID_PTE (PointerPde, TempPte);
                MiInitializePfn (PageFrameIndex, PointerPde, 1);
                PointerPde += 1;
                StartingPte += PAGE_SIZE / sizeof(MMPTE);
                j += PAGE_SIZE / sizeof(MMPTE);
            }

            UNLOCK_PFN (OldIrql);

            if (j != 0) {
                StartingPte = MiGetPteAddress ((PCHAR)MmPagedPoolEnd + 1);
                MmNonPagedSystemStart = MiGetVirtualAddressMappedByPte (StartingPte);
                MmNumberOfSystemPtes += j;
                MiAddSystemPtes (StartingPte, j, SystemPteSpace);
                MiIncrementSystemPtes (j);
            }
        }
#endif

#if defined (_MI_DEBUG_SUB)
        if (MiTrackSubs != 0) {
            MiSubsectionTraces = ExAllocatePoolWithTag (NonPagedPool,
                                   MiTrackSubs * sizeof (MI_SUB_TRACES),
                                   'tCmM');
        }
#endif

#if defined (_MI_DEBUG_DIRTY)
        if (MiTrackDirtys != 0) {
            MiDirtyTraces = ExAllocatePoolWithTag (NonPagedPool,
                                   MiTrackDirtys * sizeof (MI_DIRTY_TRACES),
                                   'tCmM');
        }
#endif

#if defined (_MI_DEBUG_DATA)
        if (MiTrackData != 0) {
            MiDataTraces = ExAllocatePoolWithTag (NonPagedPool,
                                   MiTrackData * sizeof (MI_DATA_TRACES),
                                   'tCmM');
        }
#endif

#if DBG
        if (MmDebug & MM_DBG_DUMP_BOOT_PTES) {
            MiDumpValidAddresses ();
            MiDumpPfn ();
        }
#endif

        MmPageFaultNotifyRoutine = NULL;

#ifdef _MI_MESSAGE_SERVER
        MiInitializeMessageQueue ();
#endif

        return TRUE;
    }

    if (Phase == 1) {

#if DBG
        MmDebug |= MM_DBG_CHECK_PFN_LOCK;
#endif

#if defined(_X86_) || defined(_AMD64_)
        MiInitMachineDependent (LoaderBlock);
#endif
        MiMapBBTMemory(LoaderBlock);

        if (!MiSectionInitialization ()) {
            return FALSE;
        }

        Process = PsGetCurrentProcess ();
        if (Process->PhysicalVadList.Flink == NULL) {
            InitializeListHead (&Process->PhysicalVadList);
        }

#if defined(MM_SHARED_USER_DATA_VA)

        //
        // Create double mapped page between kernel and user mode.
        // The PTE is deliberately allocated from paged pool so that
        // it will always have a PTE itself instead of being superpaged.
        // This way, checks throughout the fault handler can assume that
        // the PTE can be checked without having to special case this.
        //

        MmSharedUserDataPte = ExAllocatePoolWithTag (PagedPool,
                                                     sizeof(MMPTE),
                                                     '  mM');

        if (MmSharedUserDataPte == NULL) {
            return FALSE;
        }

        PointerPte = MiGetPteAddress ((PVOID)KI_USER_SHARED_DATA);
        ASSERT (PointerPte->u.Hard.Valid == 1);
        PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);

        MI_MAKE_VALID_PTE (TempPte,
                           PageFrameIndex,
                           MM_READONLY,
                           PointerPte);

        *MmSharedUserDataPte = TempPte;

        Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);

        LOCK_PFN (OldIrql);

        Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE;

        UNLOCK_PFN (OldIrql);

#ifdef _X86_
        if (MmHighestUserAddress < (PVOID) MM_SHARED_USER_DATA_VA) {

            //
            // Install the PTE mapping now as faults will not because the
            // shared user data is in the system portion of the address space.
            // Note the pagetable page has already been allocated and locked
            // down.
            //

            //
            // Make the mapping user accessible.
            //

            ASSERT (MmSharedUserDataPte->u.Hard.Owner == 0);
            MmSharedUserDataPte->u.Hard.Owner = 1;

            PointerPde = MiGetPdeAddress (MM_SHARED_USER_DATA_VA);
            ASSERT (PointerPde->u.Hard.Owner == 0);
            PointerPde->u.Hard.Owner = 1;

            ASSERT (MiUseMaximumSystemSpace != 0);
            PointerPte = MiGetPteAddress (MM_SHARED_USER_DATA_VA);
            ASSERT (PointerPte->u.Hard.Valid == 0);
            MI_WRITE_VALID_PTE (PointerPte, *MmSharedUserDataPte);
        }
#endif

#endif

        MiSessionWideInitializeAddresses ();
        MiInitializeSessionWsSupport ();
        MiInitializeSessionIds ();

        //
        // Start the modified page writer.
        //

        InitializeObjectAttributes (&ObjectAttributes, NULL, 0, NULL, NULL);

        if (!NT_SUCCESS(PsCreateSystemThread(
                        &ThreadHandle,
                        THREAD_ALL_ACCESS,
                        &ObjectAttributes,
                        0L,
                        NULL,
                        MiModifiedPageWriter,
                        NULL
                        ))) {
            return FALSE;
        }
        ZwClose (ThreadHandle);

        //
        // Initialize the low and high memory events.  This must be done
        // before starting the working set manager.
        //

        if (MiInitializeMemoryEvents () == FALSE) {
            return FALSE;
        }

        //
        // Start the balance set manager.
        //
        // The balance set manager performs stack swapping and working
        // set management and requires two threads.
        //

        KeInitializeEvent (&MmWorkingSetManagerEvent,
                           SynchronizationEvent,
                           FALSE);

        InitializeObjectAttributes (&ObjectAttributes, NULL, 0, NULL, NULL);

        if (!NT_SUCCESS(PsCreateSystemThread(
                        &ThreadHandle,
                        THREAD_ALL_ACCESS,
                        &ObjectAttributes,
                        0L,
                        NULL,
                        KeBalanceSetManager,
                        NULL
                        ))) {

            return FALSE;
        }
        ZwClose (ThreadHandle);

        if (!NT_SUCCESS(PsCreateSystemThread(
                        &ThreadHandle,
                        THREAD_ALL_ACCESS,
                        &ObjectAttributes,
                        0L,
                        NULL,
                        KeSwapProcessOrStack,
                        NULL
                        ))) {

            return FALSE;
        }
        ZwClose (ThreadHandle);

#ifndef NO_POOL_CHECKS
        MiInitializeSpecialPoolCriteria ();
#endif

#if defined(_X86_)
        MiEnableKernelVerifier ();
#endif

        ExAcquireResourceExclusiveLite (&PsLoadedModuleResource, TRUE);

        NextEntry = PsLoadedModuleList.Flink;

        for ( ; NextEntry != &PsLoadedModuleList; NextEntry = NextEntry->Flink) {

            DataTableEntry = CONTAINING_RECORD(NextEntry,
                                               KLDR_DATA_TABLE_ENTRY,
                                               InLoadOrderLinks);

            NtHeaders = RtlImageNtHeader(DataTableEntry->DllBase);

            if ((NtHeaders->OptionalHeader.MajorOperatingSystemVersion >= 5) &&
                (NtHeaders->OptionalHeader.MajorImageVersion >= 5)) {
                DataTableEntry->Flags |= LDRP_ENTRY_NATIVE;
            }

            MiWriteProtectSystemImage (DataTableEntry->DllBase);
        }
        ExReleaseResourceLite (&PsLoadedModuleResource);

        InterlockedDecrement (&MiTrimInProgressCount);

        return TRUE;
    }

    if (Phase == 2) {
        MiEnablePagingTheExecutive();
        return TRUE;
    }

    return FALSE;
}

VOID
MiMapBBTMemory (
    IN PLOADER_PARAMETER_BLOCK LoaderBlock
    )

/*++

Routine Description:

    This function walks through the loader block's memory descriptor list
    and maps memory reserved for the BBT buffer into the system.

    The mapped PTEs are PDE-aligned and made user accessible.

Arguments:

    LoaderBlock - Supplies a pointer to the system loader block.

Return Value:

    None.

Environment:

    Kernel Mode Only.  System initialization.

--*/
{
    PVOID Va;
    PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
    PLIST_ENTRY NextMd;
    PFN_NUMBER NumberOfPagesMapped;
    PFN_NUMBER NumberOfPages;
    PFN_NUMBER PageFrameIndex;
    PMMPTE PointerPte;
    PMMPTE PointerPde;
    PMMPTE LastPde;
    MMPTE TempPte;

    if (BBTPagesToReserve <= 0) {
        return;
    }

    //
    // Request enough PTEs such that protection can be applied to the PDEs.
    //

    NumberOfPages = (BBTPagesToReserve + (PTE_PER_PAGE - 1)) & ~(PTE_PER_PAGE - 1);

    PointerPte = MiReserveAlignedSystemPtes ((ULONG)NumberOfPages,
                                             SystemPteSpace,
                                             MM_VA_MAPPED_BY_PDE);

    if (PointerPte == NULL) {
        BBTPagesToReserve = 0;
        return;
    }

    //
    // Allow user access to the buffer.
    //

    PointerPde = MiGetPteAddress (PointerPte);
    LastPde = MiGetPteAddress (PointerPte + NumberOfPages);

    ASSERT (LastPde != PointerPde);

    do {
        TempPte = *PointerPde;
        TempPte.u.Long |= MM_PTE_OWNER_MASK;
        MI_WRITE_VALID_PTE (PointerPde, TempPte);
        PointerPde += 1;
    } while (PointerPde < LastPde);

    KeFlushEntireTb (TRUE, TRUE);

    Va = MiGetVirtualAddressMappedByPte (PointerPte);

    TempPte = ValidUserPte;
    NumberOfPagesMapped = 0;

    NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;

    while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {

        MemoryDescriptor = CONTAINING_RECORD(NextMd,
                                             MEMORY_ALLOCATION_DESCRIPTOR,
                                             ListEntry);

        if (MemoryDescriptor->MemoryType == LoaderBBTMemory) {

            PageFrameIndex = MemoryDescriptor->BasePage;
            NumberOfPages = MemoryDescriptor->PageCount;

            if (NumberOfPagesMapped + NumberOfPages > BBTPagesToReserve) {
                NumberOfPages = BBTPagesToReserve - NumberOfPagesMapped;
            }

            NumberOfPagesMapped += NumberOfPages;

            do {

                TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
                MI_WRITE_VALID_PTE (PointerPte, TempPte);

                PointerPte += 1;
                PageFrameIndex += 1;
                NumberOfPages -= 1;
            } while (NumberOfPages);

            if (NumberOfPagesMapped == BBTPagesToReserve) {
                break;
            }
        }

        NextMd = MemoryDescriptor->ListEntry.Flink;
    }

    RtlZeroMemory(Va, BBTPagesToReserve << PAGE_SHIFT);

    //
    // Tell BBT_Init how many pages were allocated.
    //

    if (NumberOfPagesMapped < BBTPagesToReserve) {
        BBTPagesToReserve = (ULONG)NumberOfPagesMapped;
    }
    *(PULONG)Va = BBTPagesToReserve;

    //
    // At this point instrumentation code will detect the existence of
    // buffer and initialize the structures.
    //

    BBTBuffer = Va;

    PERFINFO_MMINIT_START();
}


PPHYSICAL_MEMORY_DESCRIPTOR
MmInitializeMemoryLimits (
    IN PLOADER_PARAMETER_BLOCK LoaderBlock,
    IN PBOOLEAN IncludeType,
    IN OUT PPHYSICAL_MEMORY_DESCRIPTOR InputMemory OPTIONAL
    )

/*++

Routine Description:

    This function walks through the loader block's memory
    descriptor list and builds a list of contiguous physical
    memory blocks of the desired types.

Arguments:

    LoaderBlock - Supplies a pointer the system loader block.

    IncludeType - Array of BOOLEANS of size LoaderMaximum.
                  TRUE means include this type of memory in return.

    Memory - If non-NULL, supplies the physical memory blocks to place the
             search results in.  If NULL, pool is allocated to hold the
             returned search results in - the caller must free this pool.

Return Value:

    A pointer to the physical memory blocks for the requested search or NULL
    on failure.

Environment:

    Kernel Mode Only.  System initialization.

--*/
{
    PLIST_ENTRY NextMd;
    ULONG i;
    ULONG InitialAllocation;
    PFN_NUMBER NextPage;
    PFN_NUMBER TotalPages;
    PPHYSICAL_MEMORY_DESCRIPTOR Memory;
    PPHYSICAL_MEMORY_DESCRIPTOR Memory2;
    PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;

    InitialAllocation = 0;

    if (ARGUMENT_PRESENT (InputMemory)) {
        Memory = InputMemory;
    }
    else {

        //
        // The caller wants us to allocate the return result buffer.  Size it
        // by allocating the maximum possibly needed as this should not be
        // very big (relatively).  It is the caller's responsibility to free
        // this.  Obviously this option can only be requested after pool has
        // been initialized.
        //

        NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;

        while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
            InitialAllocation += 1;
            MemoryDescriptor = CONTAINING_RECORD(NextMd,
                                                 MEMORY_ALLOCATION_DESCRIPTOR,
                                                 ListEntry);
            NextMd = MemoryDescriptor->ListEntry.Flink;
        }

        Memory = ExAllocatePoolWithTag (NonPagedPool,
                                        sizeof(PHYSICAL_MEMORY_DESCRIPTOR) + sizeof(PHYSICAL_MEMORY_RUN) * (InitialAllocation - 1),
                                        'lMmM');

        if (Memory == NULL) {
            return NULL;
        }

        Memory->NumberOfRuns = InitialAllocation;
    }

    //
    // Walk through the memory descriptors and build the physical memory list.
    //

    i = 0;
    TotalPages = 0;
    NextPage = (PFN_NUMBER) -1;

    NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;

    while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {

        MemoryDescriptor = CONTAINING_RECORD(NextMd,
                                             MEMORY_ALLOCATION_DESCRIPTOR,
                                             ListEntry);

        if (MemoryDescriptor->MemoryType < LoaderMaximum &&
            IncludeType [MemoryDescriptor->MemoryType]) {

            TotalPages += MemoryDescriptor->PageCount;

            //
            // Merge runs whenever possible.
            //

            if (MemoryDescriptor->BasePage == NextPage) {
                ASSERT (MemoryDescriptor->PageCount != 0);
                Memory->Run[i - 1].PageCount += MemoryDescriptor->PageCount;
                NextPage += MemoryDescriptor->PageCount;
            }
            else {
                Memory->Run[i].BasePage = MemoryDescriptor->BasePage;
                Memory->Run[i].PageCount = MemoryDescriptor->PageCount;
                NextPage = Memory->Run[i].BasePage + Memory->Run[i].PageCount;
                i += 1;
            }
        }
        NextMd = MemoryDescriptor->ListEntry.Flink;
    }

    ASSERT (i <= Memory->NumberOfRuns);

    if (i == 0) {

        //
        // Don't bother shrinking this as the caller will be freeing it
        // shortly as it is just an empty list.
        //

        Memory->Run[i].BasePage = 0;
        Memory->Run[i].PageCount = 0;
    }
    else if (!ARGUMENT_PRESENT (InputMemory)) {

        //
        // Shrink the buffer (if possible) now that the final size is known.
        //

        if (InitialAllocation > i) {
            Memory2 = ExAllocatePoolWithTag (NonPagedPool,
                                             sizeof(PHYSICAL_MEMORY_DESCRIPTOR) + sizeof(PHYSICAL_MEMORY_RUN) * (i - 1),
                                            'lMmM');

            if (Memory2 != NULL) {
                RtlCopyMemory (Memory2->Run,
                               Memory->Run,
                               sizeof(PHYSICAL_MEMORY_RUN) * i);

                ExFreePool (Memory);
                Memory = Memory2;
            }
        }
    }

    Memory->NumberOfRuns = i;
    Memory->NumberOfPages = TotalPages;

    return Memory;
}


PFN_NUMBER
MiPagesInLoaderBlock (
    IN PLOADER_PARAMETER_BLOCK LoaderBlock,
    IN PBOOLEAN IncludeType
    )

/*++

Routine Description:

    This function walks through the loader block's memory
    descriptor list and returns the number of pages of the desired type.

Arguments:

    LoaderBlock - Supplies a pointer the system loader block.

    IncludeType - Array of BOOLEANS of size LoaderMaximum.
                  TRUE means include this type of memory in the returned count.

Return Value:

    The number of pages of the requested type in the loader block list.

Environment:

    Kernel Mode Only.  System initialization.

--*/
{
    PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
    PLIST_ENTRY NextMd;
    PFN_NUMBER TotalPages;

    //
    // Walk through the memory descriptors counting pages.
    //

    TotalPages = 0;

    NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;

    while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {

        MemoryDescriptor = CONTAINING_RECORD(NextMd,
                                             MEMORY_ALLOCATION_DESCRIPTOR,
                                             ListEntry);

        if (MemoryDescriptor->MemoryType < LoaderMaximum &&
            IncludeType [MemoryDescriptor->MemoryType]) {

            TotalPages += MemoryDescriptor->PageCount;
        }
        NextMd = MemoryDescriptor->ListEntry.Flink;
    }

    return TotalPages;
}


static
VOID
MiMemoryLicense (
    IN PLOADER_PARAMETER_BLOCK LoaderBlock
    )

/*++

Routine Description:

    This function walks through the loader block's memory descriptor list
    and based on the system's license, ensures only the proper amount of
    physical memory is used.

Arguments:

    LoaderBlock - Supplies a pointer to the system loader block.

Return Value:

    None.

Environment:

    Kernel Mode Only.  System initialization.

--*/
{
    PLIST_ENTRY NextMd;
    PFN_NUMBER TotalPagesAllowed;
    PFN_NUMBER PageCount;
    ULONG VirtualBias;
    PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;

    //
    // The default configuration gets a maximum of 4gb physical memory.
    // On PAE machines the system continues to operate in 8-byte PTE mode.
    //

    TotalPagesAllowed = MI_DEFAULT_MAX_PAGES;

    //
    // If properly licensed (ie: DataCenter) and booted without the
    // 3gb switch, then use all available physical memory.
    //

    if (ExVerifySuite(DataCenter) == TRUE) {

        //
        // Note MmVirtualBias has not yet been initialized at the time of the
        // first call to this routine, so use the LoaderBlock directly.
        //

#if defined(_X86_)
        VirtualBias = LoaderBlock->u.I386.VirtualBias;
#else
        VirtualBias = 0;
#endif

        if (VirtualBias == 0) {

            //
            // Limit the maximum physical memory to the amount we have
            // actually physically seen in a machine inhouse.
            //

            TotalPagesAllowed = MI_DTC_MAX_PAGES;
        }
        else {

            //
            // The system is booting /3gb, so don't use more than 16gb of
            // physical memory.  This ensures enough virtual space to map
            // the PFN database.
            //

            TotalPagesAllowed = MI_DTC_BOOTED_3GB_MAX_PAGES;
        }
    }
    else if ((MmProductType != 0x00690057) &&
             (ExVerifySuite(Enterprise) == TRUE)) {

        //
        // Enforce the Advanced Server physical memory limit.
        // On PAE machines the system continues to operate in 8-byte PTE mode.
        //

        TotalPagesAllowed = MI_ADS_MAX_PAGES;
    }
    else if (ExVerifySuite(Blade) == TRUE) {

        //
        // Enforce the Blade physical memory limit.
        //

        TotalPagesAllowed = MI_BLADE_MAX_PAGES;
    }

    //
    // Walk through the memory descriptors and remove or truncate descriptors
    // that exceed the maximum physical memory to be used.
    //

    PageCount = 0;
    NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
    while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {

        MemoryDescriptor = CONTAINING_RECORD(NextMd,
                                             MEMORY_ALLOCATION_DESCRIPTOR,
                                             ListEntry);

        if ((MemoryDescriptor->MemoryType == LoaderFirmwarePermanent) ||
            (MemoryDescriptor->MemoryType == LoaderBBTMemory) ||
            (MemoryDescriptor->MemoryType == LoaderBad) ||
            (MemoryDescriptor->MemoryType == LoaderSpecialMemory)) {

                NextMd = MemoryDescriptor->ListEntry.Flink;
                continue;
        }

        PageCount += MemoryDescriptor->PageCount;

        if (PageCount <= TotalPagesAllowed) {
            NextMd = MemoryDescriptor->ListEntry.Flink;
            continue;
        }

        //
        // This descriptor needs to be removed or truncated.
        //

        if (PageCount - MemoryDescriptor->PageCount >= TotalPagesAllowed) {

            //
            // Completely remove this descriptor.
            //
            // Note since this only adjusts the links and since the entry is
            // not freed, it can still be safely referenced again below to
            // obtain the NextMd.  N.B.  This keeps the memory descriptors
            // sorted in ascending order.
            //

            RemoveEntryList (NextMd);
        }
        else {

            //
            // Truncate this descriptor.
            //

            ASSERT (PageCount - MemoryDescriptor->PageCount < TotalPagesAllowed);
            MemoryDescriptor->PageCount -= (ULONG)(PageCount - TotalPagesAllowed);
            PageCount = TotalPagesAllowed;
        }

        NextMd = MemoryDescriptor->ListEntry.Flink;
    }

    return;
}


VOID
MmFreeLoaderBlock (
    IN PLOADER_PARAMETER_BLOCK LoaderBlock
    )

/*++

Routine Description:

    This function is called as the last routine in phase 1 initialization.
    It frees memory used by the OsLoader.

Arguments:

    LoaderBlock - Supplies a pointer to the system loader block.

Return Value:

    None.

Environment:

    Kernel Mode Only.  System initialization.

--*/

{
    PLIST_ENTRY NextMd;
    PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
    ULONG i;
    PFN_NUMBER NextPhysicalPage;
    PFN_NUMBER PagesFreed;
    PMMPFN Pfn1;
    KIRQL OldIrql;
    PPHYSICAL_MEMORY_RUN RunBase;
    PPHYSICAL_MEMORY_RUN Runs;

    i = 0;
    NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;

    while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
        i += 1;
        MemoryDescriptor = CONTAINING_RECORD(NextMd,
                                             MEMORY_ALLOCATION_DESCRIPTOR,
                                             ListEntry);
        NextMd = MemoryDescriptor->ListEntry.Flink;
    }

    RunBase = ExAllocatePoolWithTag (NonPagedPool,
                                     sizeof(PHYSICAL_MEMORY_RUN) * i,
                                     'lMmM');

    if (RunBase == NULL) {
        return;
    }

    Runs = RunBase;

    //
    //
    // Walk through the memory descriptors and add pages to the
    // free list in the PFN database.
    //

    NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;

    while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {

        MemoryDescriptor = CONTAINING_RECORD(NextMd,
                                             MEMORY_ALLOCATION_DESCRIPTOR,
                                             ListEntry);


        switch (MemoryDescriptor->MemoryType) {
            case LoaderOsloaderHeap:
            case LoaderRegistryData:
            case LoaderNlsData:
            //case LoaderMemoryData:  //this has page table and other stuff.

                //
                // Capture the data to temporary storage so we won't
                // free memory we are referencing.
                //

                Runs->BasePage = MemoryDescriptor->BasePage;
                Runs->PageCount = MemoryDescriptor->PageCount;
                Runs += 1;

                break;

            default:

                break;
        }

        NextMd = MemoryDescriptor->ListEntry.Flink;
    }

    PagesFreed = 0;

    LOCK_PFN (OldIrql);

    if (Runs != RunBase) {
        Runs -= 1;
        do {
            i = (ULONG)Runs->PageCount;
            NextPhysicalPage = Runs->BasePage;

#if defined (_MI_MORE_THAN_4GB_)
            if (MiNoLowMemory != 0) {
                if (NextPhysicalPage < MiNoLowMemory) {

                    //
                    // Don't free this run as it is below the memory threshold
                    // configured for this system.
                    //

                    Runs -= 1;
                    continue;
                }
            }
#endif

            Pfn1 = MI_PFN_ELEMENT (NextPhysicalPage);
            PagesFreed += i;
            while (i != 0) {

                if (Pfn1->u3.e2.ReferenceCount == 0) {
                    if (Pfn1->u1.Flink == 0) {

                        //
                        // Set the PTE address to the physical page for
                        // virtual address alignment checking.
                        //

                        Pfn1->PteAddress =
                                   (PMMPTE)(NextPhysicalPage << PTE_SHIFT);

                        MiDetermineNode (NextPhysicalPage, Pfn1);

                        MiInsertPageInFreeList (NextPhysicalPage);
                    }
                }
                else {

                    if (NextPhysicalPage != 0) {
                        //
                        // Remove PTE and insert into the free list.  If it is
                        // a physical address within the PFN database, the PTE
                        // element does not exist and therefore cannot be updated.
                        //

                        if (!MI_IS_PHYSICAL_ADDRESS (
                                MiGetVirtualAddressMappedByPte (Pfn1->PteAddress))) {

                            //
                            // Not a physical address.
                            //

                            *(Pfn1->PteAddress) = ZeroPte;
                        }

                        MI_SET_PFN_DELETED (Pfn1);
                        MiDecrementShareCountOnly (NextPhysicalPage);
                    }
                }

                Pfn1 += 1;
                i -= 1;
                NextPhysicalPage += 1;
            }
            Runs -= 1;
        } while (Runs >= RunBase);
    }

    //
    // Since systemwide commitment was determined early in Phase 0 and
    // excluded the ranges just freed, add them back in now.
    //

    if (PagesFreed != 0) {
        InterlockedExchangeAddSizeT (&MmTotalCommitLimitMaximum, PagesFreed);
        InterlockedExchangeAddSizeT (&MmTotalCommitLimit, PagesFreed);
    }

#if defined(_X86_)

    if (MmVirtualBias != 0) {

        //
        // If the kernel has been biased to allow for 3gb of user address space,
        // then the first 16mb of memory is doubly mapped to KSEG0_BASE and to
        // ALTERNATE_BASE. Therefore, the KSEG0_BASE entries must be unmapped.
        //

        PMMPTE Pde;
        ULONG NumberOfPdes;

        NumberOfPdes = MmBootImageSize / MM_VA_MAPPED_BY_PDE;

        Pde = MiGetPdeAddress((PVOID)KSEG0_BASE);

        for (i = 0; i < NumberOfPdes; i += 1) {
            MI_WRITE_INVALID_PTE (Pde, ZeroKernelPte);
            Pde += 1;
        }
    }

#endif

    KeFlushEntireTb (TRUE, TRUE);
    UNLOCK_PFN (OldIrql);
    ExFreePool (RunBase);
    return;
}

VOID
MiBuildPagedPool (
    VOID
    )

/*++

Routine Description:

    This function is called to build the structures required for paged
    pool and initialize the pool.  Once this routine is called, paged
    pool may be allocated.

Arguments:

    None.

Return Value:

    None.

Environment:

    Kernel Mode Only.  System initialization.

--*/

{
    SIZE_T Size;
    PMMPTE PointerPte;
    PMMPTE LastPte;
    PMMPTE LastPde;
    PMMPTE PointerPde;
    MMPTE TempPte;
    PFN_NUMBER PageFrameIndex;
    PFN_NUMBER ContainingFrame;
    SIZE_T AdditionalCommittedPages;
    KIRQL OldIrql;
    ULONG i;
#if (_MI_PAGING_LEVELS >= 4)
    PMMPTE PointerPxe;
    PMMPTE PointerPxeEnd;
#endif
#if (_MI_PAGING_LEVELS >= 3)
    PVOID LastVa;
    PMMPTE PointerPpe;
    PMMPTE PointerPpeEnd;
#else
    PMMPFN Pfn1;
#endif

    i = 0;
    AdditionalCommittedPages = 0;

#if (_MI_PAGING_LEVELS < 3)

    //
    // Double map system page directory page.
    //

    PointerPte = MiGetPteAddress(PDE_BASE);

    for (i = 0 ; i < PD_PER_SYSTEM; i += 1) {
        MmSystemPageDirectory[i] = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);
        Pfn1 = MI_PFN_ELEMENT(MmSystemPageDirectory[i]);
        Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE;
        PointerPte += 1;
    }

    //
    // Was not mapped physically, map it virtually in system space.
    //

    PointerPte = MiReserveSystemPtes (PD_PER_SYSTEM, SystemPteSpace);

    if (PointerPte == NULL) {
        MiIssueNoPtesBugcheck (PD_PER_SYSTEM, SystemPteSpace);
    }

    MmSystemPagePtes = (PMMPTE)MiGetVirtualAddressMappedByPte (PointerPte);

    TempPte = ValidKernelPde;

    for (i = 0 ; i < PD_PER_SYSTEM; i += 1) {
        TempPte.u.Hard.PageFrameNumber = MmSystemPageDirectory[i];
        MI_WRITE_VALID_PTE (PointerPte, TempPte);
        PointerPte += 1;
    }

#endif

    if (MmPagedPoolMaximumDesired == TRUE) {
        MmSizeOfPagedPoolInBytes =
                    ((PCHAR)MmNonPagedSystemStart - (PCHAR)MmPagedPoolStart);
    }
    else if (MmSizeOfPagedPoolInBytes == 0) {

        //
        // A size of 0 means size the pool based on physical memory.
        //

        MmSizeOfPagedPoolInBytes = 2 * MmMaximumNonPagedPoolInBytes;
#if (_MI_PAGING_LEVELS >= 3)
        MmSizeOfPagedPoolInBytes *= 2;
#endif
    }

    if (MmIsThisAnNtAsSystem()) {
        if ((MmNumberOfPhysicalPages > ((24*1024*1024) >> PAGE_SHIFT)) &&
            (MmSizeOfPagedPoolInBytes < MM_MINIMUM_PAGED_POOL_NTAS)) {

            MmSizeOfPagedPoolInBytes = MM_MINIMUM_PAGED_POOL_NTAS;
        }
    }

    if (MmSizeOfPagedPoolInBytes >
              (ULONG_PTR)((PCHAR)MmNonPagedSystemStart - (PCHAR)MmPagedPoolStart)) {
        MmSizeOfPagedPoolInBytes =
                    ((PCHAR)MmNonPagedSystemStart - (PCHAR)MmPagedPoolStart);
    }

    Size = BYTES_TO_PAGES(MmSizeOfPagedPoolInBytes);

    if (Size < MM_MIN_INITIAL_PAGED_POOL) {
        Size = MM_MIN_INITIAL_PAGED_POOL;
    }

    if (Size > (MM_MAX_PAGED_POOL >> PAGE_SHIFT)) {
        Size = MM_MAX_PAGED_POOL >> PAGE_SHIFT;
    }

#if defined (_WIN64)

    //
    // NT64 places system mapped views directly after paged pool.  Ensure
    // enough VA space is available.
    //

    if (Size + (MmSystemViewSize >> PAGE_SHIFT) > (MM_MAX_PAGED_POOL >> PAGE_SHIFT)) {
        ASSERT (MmSizeOfPagedPoolInBytes > 2 * MmSystemViewSize);
        MmSizeOfPagedPoolInBytes -= MmSystemViewSize;
        Size = BYTES_TO_PAGES(MmSizeOfPagedPoolInBytes);
    }
#endif

    Size = (Size + (PTE_PER_PAGE - 1)) / PTE_PER_PAGE;
    MmSizeOfPagedPoolInBytes = (ULONG_PTR)Size * PAGE_SIZE * PTE_PER_PAGE;

    //
    // Set size to the number of pages in the pool.
    //

    Size = Size * PTE_PER_PAGE;

    //
    // If paged pool is really nonpagable then limit the size based
    // on how much physical memory is actually present.  Disable this
    // feature if not enough physical memory is present to do it.
    //

    if (MmDisablePagingExecutive & MM_PAGED_POOL_LOCKED_DOWN) {

        Size = MmSizeOfPagedPoolInBytes / PAGE_SIZE;

        if ((MI_NONPAGABLE_MEMORY_AVAILABLE() < 2048) ||
            (MmAvailablePages < 2048)) {
                Size = 0;
        }
        else {
            if ((SPFN_NUMBER)(Size) > MI_NONPAGABLE_MEMORY_AVAILABLE() - 2048) {
                Size = (MI_NONPAGABLE_MEMORY_AVAILABLE() - 2048);
            }

            if (Size > MmAvailablePages - 2048) {
                Size = MmAvailablePages - 2048;
            }
        }

        Size = ((Size * PAGE_SIZE) / MM_VA_MAPPED_BY_PDE) * MM_VA_MAPPED_BY_PDE;

        if ((((Size / 5) * 4) >= MmSizeOfPagedPoolInBytes) &&
            (Size >= MM_MIN_INITIAL_PAGED_POOL)) {

            MmSizeOfPagedPoolInBytes = Size;
        }
        else {
            MmDisablePagingExecutive &= ~MM_PAGED_POOL_LOCKED_DOWN;
        }

        Size = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
    }

    ASSERT ((MmSizeOfPagedPoolInBytes + (PCHAR)MmPagedPoolStart) <=
            (PCHAR)MmNonPagedSystemStart);

    ASSERT64 ((MmSizeOfPagedPoolInBytes + (PCHAR)MmPagedPoolStart + MmSystemViewSize) <=
              (PCHAR)MmNonPagedSystemStart);

    MmPagedPoolEnd = (PVOID)(((PUCHAR)MmPagedPoolStart +
                            MmSizeOfPagedPoolInBytes) - 1);

    MmPageAlignedPoolBase[PagedPool] = MmPagedPoolStart;

    //
    // Build page table page for paged pool.
    //

    PointerPde = MiGetPdeAddress (MmPagedPoolStart);

    TempPte = ValidKernelPde;

#if (_MI_PAGING_LEVELS >= 3)

    //
    // Map in all the page directory pages to span all of paged pool.
    // This removes the need for a system lookup directory.
    //

    LastVa = (PVOID)((PCHAR)MmPagedPoolEnd + MmSystemViewSize);
    PointerPpe = MiGetPpeAddress (MmPagedPoolStart);
    PointerPpeEnd = MiGetPpeAddress (LastVa);

    MiSystemViewStart = (ULONG_PTR)MmPagedPoolEnd + 1;

    PointerPde = MiGetPdeAddress (MmPagedPoolEnd) + 1;
    LastPde = MiGetPdeAddress (LastVa);

    LOCK_PFN (OldIrql);

#if (_MI_PAGING_LEVELS >= 4)
    PointerPxe = MiGetPxeAddress (MmPagedPoolStart);
    PointerPxeEnd = MiGetPxeAddress (LastVa);

    while (PointerPxe <= PointerPxeEnd) {

        if (PointerPxe->u.Hard.Valid == 0) {
            PageFrameIndex = MiRemoveAnyPage(
                                     MI_GET_PAGE_COLOR_FROM_PTE (PointerPxe));
            TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
            MI_WRITE_VALID_PTE (PointerPxe, TempPte);

            MiInitializePfn (PageFrameIndex, PointerPxe, 1);

            //
            // Make all entries no access since the PDEs may not fill the page.
            //

            MiFillMemoryPte (MiGetVirtualAddressMappedByPte (PointerPxe),
                             PAGE_SIZE,
                             MM_KERNEL_NOACCESS_PTE);

            MmResidentAvailablePages -= 1;
            AdditionalCommittedPages += 1;
        }

        PointerPxe += 1;
    }
#endif

    while (PointerPpe <= PointerPpeEnd) {

        if (PointerPpe->u.Hard.Valid == 0) {
            PageFrameIndex = MiRemoveAnyPage(
                                     MI_GET_PAGE_COLOR_FROM_PTE (PointerPpe));
            TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
            MI_WRITE_VALID_PTE (PointerPpe, TempPte);

            MiInitializePfn (PageFrameIndex, PointerPpe, 1);

            //
            // Make all entries no access since the PDEs may not fill the page.
            //

            MiFillMemoryPte (MiGetVirtualAddressMappedByPte (PointerPpe),
                             PAGE_SIZE,
                             MM_KERNEL_NOACCESS_PTE);

            MmResidentAvailablePages -= 1;
            AdditionalCommittedPages += 1;
        }

        PointerPpe += 1;
    }

    //
    // Initialize the system view page table pages.
    //

    MmResidentAvailablePages -= (LastPde - PointerPde + 1);
    AdditionalCommittedPages += (LastPde - PointerPde + 1);

    while (PointerPde <= LastPde) {

        ASSERT (PointerPde->u.Hard.Valid == 0);

        PageFrameIndex = MiRemoveAnyPage(
                            MI_GET_PAGE_COLOR_FROM_PTE (PointerPde));
        TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
        MI_WRITE_VALID_PTE (PointerPde, TempPte);

        MiInitializePfn (PageFrameIndex, PointerPde, 1);

        MiFillMemoryPte (MiGetVirtualAddressMappedByPte (PointerPde),
                        PAGE_SIZE,
                        ZeroKernelPte.u.Long);

        PointerPde += 1;
    }

    UNLOCK_PFN (OldIrql);

    PointerPde = MiGetPdeAddress (MmPagedPoolStart);

#endif

    PointerPte = MiGetPteAddress (MmPagedPoolStart);
    MmPagedPoolInfo.FirstPteForPagedPool = PointerPte;
    MmPagedPoolInfo.LastPteForPagedPool = MiGetPteAddress (MmPagedPoolEnd);

    MiFillMemoryPte (PointerPde,
                     sizeof(MMPTE) *
                         (1 + MiGetPdeAddress (MmPagedPoolEnd) - PointerPde),
                     MM_KERNEL_NOACCESS_PTE);

    LOCK_PFN (OldIrql);

    //
    // Map in a page table page.
    //

    PageFrameIndex = MiRemoveAnyPage(
                            MI_GET_PAGE_COLOR_FROM_PTE (PointerPde));
    TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
    MI_WRITE_VALID_PTE (PointerPde, TempPte);

#if (_MI_PAGING_LEVELS >= 3)
    ContainingFrame = MI_GET_PAGE_FRAME_FROM_PTE(MiGetPpeAddress (MmPagedPoolStart));
#else
    ContainingFrame = MmSystemPageDirectory[(PointerPde - MiGetPdeAddress(0)) / PDE_PER_PAGE];
#endif

    MiInitializePfnForOtherProcess (PageFrameIndex,
                                    PointerPde,
                                    ContainingFrame);

    MiFillMemoryPte (PointerPte, PAGE_SIZE, MM_KERNEL_NOACCESS_PTE);

    UNLOCK_PFN (OldIrql);

    MmPagedPoolInfo.NextPdeForPagedPoolExpansion = PointerPde + 1;

    //
    // Build bitmaps for paged pool.
    //

    MiCreateBitMap (&MmPagedPoolInfo.PagedPoolAllocationMap, Size, NonPagedPool);
    RtlSetAllBits (MmPagedPoolInfo.PagedPoolAllocationMap);

    //
    // Indicate first page worth of PTEs are available.
    //

    RtlClearBits (MmPagedPoolInfo.PagedPoolAllocationMap, 0, PTE_PER_PAGE);

    MiCreateBitMap (&MmPagedPoolInfo.EndOfPagedPoolBitmap, Size, NonPagedPool);
    RtlClearAllBits (MmPagedPoolInfo.EndOfPagedPoolBitmap);

    //
    // If verifier is present then build the verifier paged pool bitmap.
    //

    if (MmVerifyDriverBufferLength != (ULONG)-1) {
        MiCreateBitMap (&VerifierLargePagedPoolMap, Size, NonPagedPool);
        RtlClearAllBits (VerifierLargePagedPoolMap);
    }

    //
    // Initialize paged pool.
    //

    InitializePool (PagedPool, 0L);

    //
    // If paged pool is really nonpagable then allocate the memory now.
    //

    if (MmDisablePagingExecutive & MM_PAGED_POOL_LOCKED_DOWN) {

        PointerPde = MiGetPdeAddress (MmPagedPoolStart);
        PointerPde += 1;
        LastPde = MiGetPdeAddress (MmPagedPoolEnd);
        TempPte = ValidKernelPde;

        PointerPte = MiGetPteAddress (MmPagedPoolStart);
        LastPte = MiGetPteAddress (MmPagedPoolEnd);

        ASSERT (MmPagedPoolCommit == 0);
        MmPagedPoolCommit = (ULONG)(LastPte - PointerPte + 1);

        ASSERT (MmPagedPoolInfo.PagedPoolCommit == 0);
        MmPagedPoolInfo.PagedPoolCommit = MmPagedPoolCommit;

#if DBG
        //
        // Ensure no paged pool has been allocated yet.
        //

        for (i = 0; i < PTE_PER_PAGE; i += 1) {
            ASSERT (!RtlCheckBit (MmPagedPoolInfo.PagedPoolAllocationMap, i));
        }

        while (i < MmSizeOfPagedPoolInBytes / PAGE_SIZE) {
            ASSERT (RtlCheckBit (MmPagedPoolInfo.PagedPoolAllocationMap, i));
            i += 1;
        }
#endif

        RtlClearAllBits (MmPagedPoolInfo.PagedPoolAllocationMap);

        LOCK_PFN (OldIrql);

        //
        // Map in the page table pages.
        //

        MmResidentAvailablePages -= (LastPde - PointerPde + 1);
        AdditionalCommittedPages += (LastPde - PointerPde + 1);

        while (PointerPde <= LastPde) {

            ASSERT (PointerPde->u.Hard.Valid == 0);

            PageFrameIndex = MiRemoveAnyPage(
                                    MI_GET_PAGE_COLOR_FROM_PTE (PointerPde));
            TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
            MI_WRITE_VALID_PTE (PointerPde, TempPte);

#if (_MI_PAGING_LEVELS >= 3)
            ContainingFrame = MI_GET_PAGE_FRAME_FROM_PTE(MiGetPteAddress (PointerPde));
#else
            ContainingFrame = MmSystemPageDirectory[(PointerPde - MiGetPdeAddress(0)) / PDE_PER_PAGE];
#endif

            MiInitializePfnForOtherProcess (PageFrameIndex,
                                            MiGetPteAddress (PointerPde),
                                            ContainingFrame);

            MiFillMemoryPte (MiGetVirtualAddressMappedByPte (PointerPde),
                             PAGE_SIZE,
                             MM_KERNEL_NOACCESS_PTE);

            PointerPde += 1;
        }

        MmPagedPoolInfo.NextPdeForPagedPoolExpansion = PointerPde;

        TempPte = ValidKernelPte;
        MI_SET_PTE_DIRTY (TempPte);

        ASSERT (MmAvailablePages > (PFN_COUNT)(LastPte - PointerPte + 1));
        ASSERT (MmResidentAvailablePages > (SPFN_NUMBER)(LastPte - PointerPte + 1));
        MmResidentAvailablePages -= (LastPte - PointerPte + 1);
        AdditionalCommittedPages += (LastPte - PointerPte + 1);

        while (PointerPte <= LastPte) {

            ASSERT (PointerPte->u.Hard.Valid == 0);

            PageFrameIndex = MiRemoveAnyPage(
                                    MI_GET_PAGE_COLOR_FROM_PTE (PointerPte));
            TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
            MI_WRITE_VALID_PTE (PointerPte, TempPte);

            MiInitializePfn (PageFrameIndex, PointerPte, 1);

            PointerPte += 1;
        }

        UNLOCK_PFN (OldIrql);
    }

    //
    // Since the commitment return path is lock free, the total committed
    // page count must be atomically incremented.
    //

    InterlockedExchangeAddSizeT (&MmTotalCommittedPages, AdditionalCommittedPages);

    MiInitializeSpecialPool (NonPagedPool);

    //
    // Allow mapping of views into system space.
    //

    MiInitializeSystemSpaceMap (NULL);

    return;
}


VOID
MiFindInitializationCode (
    OUT PVOID *StartVa,
    OUT PVOID *EndVa
    )

/*++

Routine Description:

    This function locates the start and end of the kernel initialization
    code.  This code resides in the "init" section of the kernel image.

Arguments:

    StartVa - Returns the starting address of the init section.

    EndVa - Returns the ending address of the init section.

Return Value:

    None.

Environment:

    Kernel Mode Only.  End of system initialization.

--*/

{
    PKLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
    PVOID CurrentBase;
    PVOID InitStart;
    PVOID InitEnd;
    PLIST_ENTRY Next;
    PIMAGE_NT_HEADERS NtHeader;
    PIMAGE_SECTION_HEADER SectionTableEntry;
    PIMAGE_SECTION_HEADER LastDiscard;
    LONG i;
    LOGICAL DiscardSection;
    PVOID MiFindInitializationCodeAddress;
    PKTHREAD CurrentThread;

    MiFindInitializationCodeAddress = MmGetProcedureAddress((PVOID)(ULONG_PTR)&MiFindInitializationCode);

#if defined(_IA64_)

    //
    // One more indirection is needed due to the PLABEL.
    //

    MiFindInitializationCodeAddress = (PVOID)(*((PULONGLONG)MiFindInitializationCodeAddress));

#endif

    *StartVa = NULL;

    //
    // Walk through the loader blocks looking for the base which
    // contains this routine.
    //

    CurrentThread = KeGetCurrentThread ();
    KeEnterCriticalRegionThread (CurrentThread);
    ExAcquireResourceExclusiveLite (&PsLoadedModuleResource, TRUE);
    Next = PsLoadedModuleList.Flink;

    while (Next != &PsLoadedModuleList) {
        LdrDataTableEntry = CONTAINING_RECORD (Next,
                                               KLDR_DATA_TABLE_ENTRY,
                                               InLoadOrderLinks);

        if (LdrDataTableEntry->SectionPointer != NULL) {

            //
            // This entry was loaded by MmLoadSystemImage so it's already
            // had its init section removed.
            //

            Next = Next->Flink;
            continue;
        }

        CurrentBase = (PVOID)LdrDataTableEntry->DllBase;
        NtHeader = RtlImageNtHeader(CurrentBase);

        SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeader +
                                sizeof(ULONG) +
                                sizeof(IMAGE_FILE_HEADER) +
                                NtHeader->FileHeader.SizeOfOptionalHeader);

        //
        // From the image header, locate the sections named 'INIT',
        // PAGEVRF* and PAGESPEC.  INIT always goes, the others go depending
        // on registry configuration.
        //

        i = NtHeader->FileHeader.NumberOfSections;

        InitStart = NULL;
        while (i > 0) {

#if DBG
            if ((*(PULONG)SectionTableEntry->Name == 'tini') ||
                (*(PULONG)SectionTableEntry->Name == 'egap')) {
                DbgPrint("driver %wZ has lower case sections (init or pagexxx)\n",
                    &LdrDataTableEntry->FullDllName);
            }
#endif

            DiscardSection = FALSE;

            //
            // Free any INIT sections (or relocation sections that haven't
            // been already).  Note a driver may have a relocation section
            // but not have any INIT code.
            //

            if ((*(PULONG)SectionTableEntry->Name == 'TINI') ||
                ((SectionTableEntry->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0)) {
                DiscardSection = TRUE;
            }
            else if ((*(PULONG)SectionTableEntry->Name == 'EGAP') &&
                     (SectionTableEntry->Name[4] == 'V') &&
                     (SectionTableEntry->Name[5] == 'R') &&
                     (SectionTableEntry->Name[6] == 'F')) {

                //
                // Discard PAGEVRF* if no drivers are being instrumented.
                //

                if (MmVerifyDriverBufferLength == (ULONG)-1) {
                    DiscardSection = TRUE;
                }
            }
            else if ((*(PULONG)SectionTableEntry->Name == 'EGAP') &&
                (*(PULONG)&SectionTableEntry->Name[4] == 'CEPS')) {

                //
                // Discard PAGESPEC special pool code if it's not enabled.
                //

                if (MiSpecialPoolFirstPte == NULL) {
                    DiscardSection = TRUE;
                }
            }

            if (DiscardSection == TRUE) {

                InitStart = (PVOID)((PCHAR)CurrentBase + SectionTableEntry->VirtualAddress);
                InitEnd = (PVOID)((PCHAR)InitStart + SectionTableEntry->SizeOfRawData - 1);
                InitEnd = (PVOID)((PCHAR)PAGE_ALIGN ((PCHAR)InitEnd +
                        (NtHeader->OptionalHeader.SectionAlignment - 1)) - 1);
                InitStart = (PVOID)ROUND_TO_PAGES (InitStart);

                //
                // Check if more sections are discardable after this one so
                // even small INIT sections can be discarded.
                //

                if (i == 1) {
                    LastDiscard = SectionTableEntry;
                }
                else {
                    LastDiscard = NULL;
                    do {
                        i -= 1;
                        SectionTableEntry += 1;

                        if ((SectionTableEntry->Characteristics &
                             IMAGE_SCN_MEM_DISCARDABLE) != 0) {

                            //
                            // Discard this too.
                            //

                            LastDiscard = SectionTableEntry;
                        }
                        else {
                            break;
                        }
                    } while (i > 1);
                }

                if (LastDiscard) {
                    InitEnd = (PVOID)(((PCHAR)CurrentBase +
                                       LastDiscard->VirtualAddress) +
                                      (LastDiscard->SizeOfRawData - 1));

                    //
                    // If this isn't the last section in the driver then the
                    // the next section is not discardable.  So the last
                    // section is not rounded down, but all others must be.
                    //

                    if (i != 1) {
                        InitEnd = (PVOID)((PCHAR)PAGE_ALIGN ((PCHAR)InitEnd +
                                                             (NtHeader->OptionalHeader.SectionAlignment - 1)) - 1);
                    }
                }

                if (InitEnd > (PVOID)((PCHAR)CurrentBase +
                                      LdrDataTableEntry->SizeOfImage)) {
                    InitEnd = (PVOID)(((ULONG_PTR)CurrentBase +
                                       (LdrDataTableEntry->SizeOfImage - 1)) |
                                      (PAGE_SIZE - 1));
                }

                if (InitStart <= InitEnd) {
                    if ((MiFindInitializationCodeAddress >= InitStart) &&
                        (MiFindInitializationCodeAddress <= InitEnd)) {

                        //
                        // This init section is in the kernel, don't free it
                        // now as it would free this code!
                        //

                        ASSERT (*StartVa == NULL);
                        *StartVa = InitStart;
                        *EndVa = InitEnd;
                    }
                    else {
                        MiFreeInitializationCode (InitStart, InitEnd);
                    }
                }
            }
            i -= 1;
            SectionTableEntry += 1;
        }
        Next = Next->Flink;
    }
    ExReleaseResourceLite (&PsLoadedModuleResource);
    KeLeaveCriticalRegionThread (CurrentThread);
    return;
}


VOID
MiFreeInitializationCode (
    IN PVOID StartVa,
    IN PVOID EndVa
    )

/*++

Routine Description:

    This function is called to delete the initialization code.

Arguments:

    StartVa - Supplies the starting address of the range to delete.

    EndVa - Supplies the ending address of the range to delete.

Return Value:

    None.

Environment:

    Kernel Mode Only.  Runs after system initialization.

--*/

{
    PMMPFN Pfn1;
    PMMPTE PointerPte;
    PFN_NUMBER PageFrameIndex;
    PFN_NUMBER PagesFreed;
    KIRQL OldIrql;

    ASSERT(ExPageLockHandle);

#if defined (_MI_MORE_THAN_4GB_)
    if (MiNoLowMemory != 0) {

        //
        // Don't free this range as the kernel is always below the memory
        // threshold configured for this system.
        //

        return;
    }
#endif

    PagesFreed = 0;
    MmLockPagableSectionByHandle(ExPageLockHandle);

    if (MI_IS_PHYSICAL_ADDRESS(StartVa)) {
        LOCK_PFN (OldIrql);
        while (StartVa < EndVa) {

            //
            // On certain architectures (e.g., MIPS) virtual addresses
            // may be physical and hence have no corresponding PTE.
            //

            PageFrameIndex = MI_CONVERT_PHYSICAL_TO_PFN (StartVa);

            Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
            Pfn1->u2.ShareCount = 0;
            Pfn1->u3.e2.ReferenceCount = 0;
            MI_SET_PFN_DELETED (Pfn1);
            MiInsertPageInFreeList (PageFrameIndex);
            StartVa = (PVOID)((PUCHAR)StartVa + PAGE_SIZE);
            PagesFreed += 1;
        }
        UNLOCK_PFN (OldIrql);
    }
    else {
        PointerPte = MiGetPteAddress (StartVa);
        PagesFreed = MiDeleteSystemPagableVm (PointerPte,
                                 (PFN_NUMBER) (1 + MiGetPteAddress (EndVa) -
                                     PointerPte),
                                 ZeroKernelPte,
                                 FALSE,
                                 NULL);
    }
    MmUnlockPagableImageSection(ExPageLockHandle);

    //
    // Since systemwide commitment was determined early in Phase 0 and
    // excluded the ranges just freed, add them back in now.
    //

    if (PagesFreed != 0) {

        //
        // Since systemwide commitment was determined early in Phase 0
        // and excluded the ranges just freed, increase the limits
        // accordingly now.  Note that there is no commitment to be
        // returned (as none was ever charged earlier) for boot
        // loaded drivers.
        //

        InterlockedExchangeAddSizeT (&MmTotalCommitLimitMaximum, PagesFreed);
        InterlockedExchangeAddSizeT (&MmTotalCommitLimit, PagesFreed);
    }

    return;
}


VOID
MiEnablePagingTheExecutive (
    VOID
    )

/*++

Routine Description:

    This function locates the start and end of the kernel initialization
    code.  This code resides in the "init" section of the kernel image.

Arguments:

    StartVa - Returns the starting address of the init section.

    EndVa - Returns the ending address of the init section.

Return Value:

    None.

Environment:

    Kernel Mode Only.  End of system initialization.

--*/

{
    KIRQL OldIrql;
    KIRQL OldIrqlWs;
    PVOID StartVa;
    PETHREAD CurrentThread;
    PLONG SectionLockCountPointer;
    PKLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
    PVOID CurrentBase;
    PLIST_ENTRY Next;
    PIMAGE_NT_HEADERS NtHeader;
    PIMAGE_SECTION_HEADER StartSectionTableEntry;
    PIMAGE_SECTION_HEADER SectionTableEntry;
    LONG i;
    PMMPTE PointerPte;
    PMMPTE LastPte;
    PMMPTE SubsectionStartPte;
    PMMPTE SubsectionLastPte;
    LOGICAL PageSection;
    PVOID SectionBaseAddress;
    LOGICAL AlreadyLockedOnce;
    ULONG Waited;
    PEPROCESS CurrentProcess;

    //
    // Don't page kernel mode code if customer does not want it paged or if
    // this is a diskless remote boot client.
    //

    if (MmDisablePagingExecutive & MM_SYSTEM_CODE_LOCKED_DOWN) {
        return;
    }

#if defined(REMOTE_BOOT)
    if (IoRemoteBootClient && IoCscInitializationFailed) {
        return;
    }
#endif

    //
    // Initializing LastPte is not needed for correctness, but
    // without it the compiler cannot compile this code W4 to check
    // for use of uninitialized variables.
    //

    LastPte = NULL;

    //
    // Walk through the loader blocks looking for the base which
    // contains this routine.
    //

    CurrentThread = PsGetCurrentThread ();
    CurrentProcess = PsGetCurrentProcessByThread (CurrentThread);

    KeEnterCriticalRegionThread (&CurrentThread->Tcb);
    ExAcquireResourceExclusiveLite (&PsLoadedModuleResource, TRUE);
    Next = PsLoadedModuleList.Flink;

    while (Next != &PsLoadedModuleList) {

        LdrDataTableEntry = CONTAINING_RECORD (Next,
                                               KLDR_DATA_TABLE_ENTRY,
                                               InLoadOrderLinks);

        if (LdrDataTableEntry->SectionPointer != NULL) {

            //
            // This entry was loaded by MmLoadSystemImage so it's already paged.
            //

            Next = Next->Flink;
            continue;
        }

        CurrentBase = (PVOID)LdrDataTableEntry->DllBase;

        if (MI_IS_PHYSICAL_ADDRESS (CurrentBase)) {

            //
            // Mapped physically, can't be paged.
            //

            Next = Next->Flink;
            continue;
        }

        NtHeader = RtlImageNtHeader (CurrentBase);

restart:

        StartSectionTableEntry = NULL;
        SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeader +
                                sizeof(ULONG) +
                                sizeof(IMAGE_FILE_HEADER) +
                                NtHeader->FileHeader.SizeOfOptionalHeader);

        //
        // From the image header, locate the section named 'PAGE' or '.edata'.
        //

        i = NtHeader->FileHeader.NumberOfSections;

        PointerPte = NULL;

        while (i > 0) {

            SectionBaseAddress = SECTION_BASE_ADDRESS(SectionTableEntry);

            if ((PUCHAR)SectionBaseAddress ==
                            ((PUCHAR)CurrentBase + SectionTableEntry->VirtualAddress)) {
                AlreadyLockedOnce = TRUE;

                //
                // This subsection has already been locked down (and possibly
                // unlocked as well) at least once.  If it is NOT locked down
                // right now and the pages are not in the system working set
                // then include it in the chunk to be paged.
                //

                SectionLockCountPointer = SECTION_LOCK_COUNT_POINTER (SectionTableEntry);

                if (*SectionLockCountPointer == 0) {

                    SubsectionStartPte = MiGetPteAddress ((PVOID)(ROUND_TO_PAGES (
                                  (ULONG_PTR)CurrentBase +
                                  SectionTableEntry->VirtualAddress)));

                    SubsectionLastPte = MiGetPteAddress ((PVOID)((ULONG_PTR)CurrentBase +
                                 SectionTableEntry->VirtualAddress +
                                 (NtHeader->OptionalHeader.SectionAlignment - 1) +
                                 SectionTableEntry->SizeOfRawData -
                                 PAGE_SIZE));

                    if (SubsectionLastPte >= SubsectionStartPte) {
                        AlreadyLockedOnce = FALSE;
                    }
                }
            }
            else {
                AlreadyLockedOnce = FALSE;
            }

            PageSection = ((*(PULONG)SectionTableEntry->Name == 'EGAP') ||
                          (*(PULONG)SectionTableEntry->Name == 'ade.')) &&
                           (AlreadyLockedOnce == FALSE);

            if (*(PULONG)SectionTableEntry->Name == 'EGAP' &&
                SectionTableEntry->Name[4] == 'K'  &&
                SectionTableEntry->Name[5] == 'D') {

                //
                // Only pageout PAGEKD if KdPitchDebugger is TRUE.
                //

                PageSection = KdPitchDebugger;
            }

            if ((*(PULONG)SectionTableEntry->Name == 'EGAP') &&
                     (SectionTableEntry->Name[4] == 'V') &&
                     (SectionTableEntry->Name[5] == 'R') &&
                     (SectionTableEntry->Name[6] == 'F')) {

                //
                // Pageout PAGEVRF* if no drivers are being instrumented.
                //

                if (MmVerifyDriverBufferLength != (ULONG)-1) {
                    PageSection = FALSE;
                }
            }

            if ((*(PULONG)SectionTableEntry->Name == 'EGAP') &&
                (*(PULONG)&SectionTableEntry->Name[4] == 'CEPS')) {

                //
                // Pageout PAGESPEC special pool code if it's not enabled.
                //

                if (MiSpecialPoolFirstPte != NULL) {
                    PageSection = FALSE;
                }
            }

            if (PageSection) {

                 //
                 // This section is pagable, save away the start and end.
                 //

                 if (PointerPte == NULL) {

                     //
                     // Previous section was NOT pagable, get the start address.
                     //

                     ASSERT (StartSectionTableEntry == NULL);
                     StartSectionTableEntry = SectionTableEntry;
                     PointerPte = MiGetPteAddress ((PVOID)(ROUND_TO_PAGES (
                                  (ULONG_PTR)CurrentBase +
                                  SectionTableEntry->VirtualAddress)));
                 }
                 LastPte = MiGetPteAddress ((PVOID)((ULONG_PTR)CurrentBase +
                             SectionTableEntry->VirtualAddress +
                             (NtHeader->OptionalHeader.SectionAlignment - 1) +
                             SectionTableEntry->SizeOfRawData -
                             PAGE_SIZE));
            }
            else {

                //
                // This section is not pagable, if the previous section was
                // pagable, enable it.
                //

                if (PointerPte != NULL) {

                    ASSERT (StartSectionTableEntry != NULL);
                    LOCK_SYSTEM_WS (OldIrqlWs, CurrentThread);
                    LOCK_PFN (OldIrql);

                    StartVa = PAGE_ALIGN (StartSectionTableEntry);
                    while (StartVa < (PVOID) SectionTableEntry) {
                        Waited = MiMakeSystemAddressValidPfnSystemWs (StartVa);
                        if (Waited != 0) {

                            //
                            // Restart at the top as the locks were released.
                            //

                            UNLOCK_PFN (OldIrql);
                            UNLOCK_SYSTEM_WS (OldIrqlWs);
                            goto restart;
                        }
                        StartVa = (PVOID)((PCHAR)StartVa + PAGE_SIZE);
                    }

                    //
                    // Now that we're holding the proper locks, rewalk all
                    // the sections to make sure they weren't locked down
                    // after we checked above.
                    //

                    while (StartSectionTableEntry < SectionTableEntry) {
                        SectionBaseAddress = SECTION_BASE_ADDRESS(StartSectionTableEntry);

                        SectionLockCountPointer = SECTION_LOCK_COUNT_POINTER (StartSectionTableEntry);
                        if (((PUCHAR)SectionBaseAddress ==
                                        ((PUCHAR)CurrentBase + StartSectionTableEntry->VirtualAddress)) &&
                        (*SectionLockCountPointer != 0)) {

                            //
                            // Restart at the top as the section has been
                            // explicitly locked by a driver since we first
                            // checked above.
                            //

                            UNLOCK_PFN (OldIrql);
                            UNLOCK_SYSTEM_WS (OldIrqlWs);
                            goto restart;
                        }
                        StartSectionTableEntry += 1;
                    }

                    MiEnablePagingOfDriverAtInit (PointerPte, LastPte);

                    UNLOCK_PFN (OldIrql);
                    UNLOCK_SYSTEM_WS (OldIrqlWs);

                    PointerPte = NULL;
                    StartSectionTableEntry = NULL;
                }
            }
            i -= 1;
            SectionTableEntry += 1;
        }

        if (PointerPte != NULL) {
            ASSERT (StartSectionTableEntry != NULL);
            LOCK_SYSTEM_WS (OldIrqlWs, CurrentThread);
            LOCK_PFN (OldIrql);

            StartVa = PAGE_ALIGN (StartSectionTableEntry);
            while (StartVa < (PVOID) SectionTableEntry) {
                Waited = MiMakeSystemAddressValidPfnSystemWs (StartVa);
                if (Waited != 0) {

                    //
                    // Restart at the top as the locks were released.
                    //

                    UNLOCK_PFN (OldIrql);
                    UNLOCK_SYSTEM_WS (OldIrqlWs);
                    goto restart;
                }
                StartVa = (PVOID)((PCHAR)StartVa + PAGE_SIZE);
            }

            //
            // Now that we're holding the proper locks, rewalk all
            // the sections to make sure they weren't locked down
            // after we checked above.
            //

            while (StartSectionTableEntry < SectionTableEntry) {
                SectionBaseAddress = SECTION_BASE_ADDRESS(StartSectionTableEntry);

                SectionLockCountPointer = SECTION_LOCK_COUNT_POINTER (StartSectionTableEntry);
                if (((PUCHAR)SectionBaseAddress ==
                                ((PUCHAR)CurrentBase + StartSectionTableEntry->VirtualAddress)) &&
                (*SectionLockCountPointer != 0)) {

                    //
                    // Restart at the top as the section has been
                    // explicitly locked by a driver since we first
                    // checked above.
                    //

                    UNLOCK_PFN (OldIrql);
                    UNLOCK_SYSTEM_WS (OldIrqlWs);
                    goto restart;
                }
                StartSectionTableEntry += 1;
            }
            MiEnablePagingOfDriverAtInit (PointerPte, LastPte);

            UNLOCK_PFN (OldIrql);
            UNLOCK_SYSTEM_WS (OldIrqlWs);
        }

        Next = Next->Flink;
    }

    ExReleaseResourceLite (&PsLoadedModuleResource);
    KeLeaveCriticalRegionThread (&CurrentThread->Tcb);

    return;
}


VOID
MiEnablePagingOfDriverAtInit (
    IN PMMPTE PointerPte,
    IN PMMPTE LastPte
    )

/*++

Routine Description:

    This routine marks the specified range of PTEs as pagable.

Arguments:

    PointerPte - Supplies the starting PTE.

    LastPte - Supplies the ending PTE.

Return Value:

    None.

Environment:

    Working set mutex AND PFN lock held.

--*/

{
    PVOID Base;
    PFN_NUMBER PageFrameIndex;
    PMMPFN Pfn;
    MMPTE TempPte;
    LOGICAL SessionAddress;

    MM_PFN_LOCK_ASSERT();

    Base = MiGetVirtualAddressMappedByPte (PointerPte);
    SessionAddress = MI_IS_SESSION_PTE (PointerPte);

    while (PointerPte <= LastPte) {

        //
        // The PTE must be carefully checked as drivers may call MmPageEntire
        // during their DriverEntry yet faults may occur prior to this routine
        // running which cause pages to already be resident and in the working
        // set at this point.  So checks for validity and wsindex must be
        // applied.
        //

        if (PointerPte->u.Hard.Valid == 1) {
            PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte);
            Pfn = MI_PFN_ELEMENT (PageFrameIndex);
            ASSERT (Pfn->u2.ShareCount == 1);

            if (Pfn->u1.WsIndex == 0) {

                //
                // Set the working set index to zero.  This allows page table
                // pages to be brought back in with the proper WSINDEX.
                //

                MI_ZERO_WSINDEX (Pfn);

                //
                // Original PTE may need to be set for drivers loaded via
                // ntldr.
                //

                if (Pfn->OriginalPte.u.Long == 0) {
                    Pfn->OriginalPte.u.Long = MM_KERNEL_DEMAND_ZERO_PTE;
                    Pfn->OriginalPte.u.Soft.Protection |= MM_EXECUTE;
                }

                MI_SET_MODIFIED (Pfn, 1, 0x11);

                TempPte = *PointerPte;

                MI_MAKE_VALID_PTE_TRANSITION (TempPte,
                                              Pfn->OriginalPte.u.Soft.Protection);

                KeFlushSingleTb (Base,
                                 TRUE,
                                 TRUE,
                                 (PHARDWARE_PTE)PointerPte,
                                 TempPte.u.Flush);

                //
                // Flush the translation buffer and decrement the number of valid
                // PTEs within the containing page table page.  Note that for a
                // private page, the page table page is still needed because the
                // page is in transition.
                //

                MiDecrementShareCount (PageFrameIndex);

                MmResidentAvailablePages += 1;
                MmTotalSystemCodePages += 1;
            }
            else {

                //
                // This would need to be taken out of the WSLEs so skip it for
                // now and let the normal paging algorithms remove it if we
                // run into memory pressure.
                //
            }

        }
        Base = (PVOID)((PCHAR)Base + PAGE_SIZE);
        PointerPte += 1;
    }

    if (SessionAddress == TRUE) {

        //
        // Session space has no ASN - flush the entire TB.
        //

        MI_FLUSH_ENTIRE_SESSION_TB (TRUE, TRUE);
    }

    return;
}


MM_SYSTEMSIZE
MmQuerySystemSize(
    VOID
    )
{
    //
    // 12Mb  is small
    // 12-19 is medium
    // > 19 is large
    //
    return MmSystemSize;
}

NTKERNELAPI
BOOLEAN
MmIsThisAnNtAsSystem(
    VOID
    )
{
    return (BOOLEAN)MmProductType;
}

NTKERNELAPI
VOID
FASTCALL
MmSetPageFaultNotifyRoutine(
    PPAGE_FAULT_NOTIFY_ROUTINE NotifyRoutine
    )
{
    MmPageFaultNotifyRoutine = NotifyRoutine;
}

#ifdef _MI_MESSAGE_SERVER

LIST_ENTRY MiMessageInfoListHead;
KSPIN_LOCK MiMessageLock;
KEVENT MiMessageEvent;
ULONG MiMessageCount;

VOID
MiInitializeMessageQueue (
    VOID
    )
{
    MiMessageCount = 0;
    InitializeListHead (&MiMessageInfoListHead);
    KeInitializeSpinLock (&MiMessageLock);

    //
    // Use a synchronization event so the event's signal state is
    // auto cleared on a successful wait.
    //

    KeInitializeEvent (&MiMessageEvent, SynchronizationEvent, FALSE);
}

LOGICAL
MiQueueMessage (
    IN PVOID Message
    )
{
    KIRQL OldIrql;
    LOGICAL Enqueued;

    Enqueued = TRUE;
    ExAcquireSpinLock (&MiMessageLock, &OldIrql);

    if (MiMessageCount <= 500) {
        InsertTailList (&MiMessageInfoListHead, (PLIST_ENTRY)Message);
        MiMessageCount += 1;
    }
    else {
        Enqueued = FALSE;
    }

    ExReleaseSpinLock (&MiMessageLock, OldIrql);

    if (Enqueued == TRUE) {
        KeSetEvent (&MiMessageEvent, 0, FALSE);
    }
    else {
        ExFreePool (Message);
    }

    return Enqueued;
}

//
// sr: free the pool when done.
//

PVOID
MiRemoveMessage (
    VOID
    )
{
    PVOID Message;
    KIRQL OldIrql;
    NTSTATUS Status;

    Message = NULL;

    //
    // N.B.  waiting with a timeout and return so caller can support unload.
    //

    Status = KeWaitForSingleObject (&MiMessageEvent,
                                    WrVirtualMemory,
                                    KernelMode,
                                    FALSE,
                                    (PLARGE_INTEGER) &MmTwentySeconds);

    if (Status != STATUS_TIMEOUT) {

        ExAcquireSpinLock (&MiMessageLock, &OldIrql);

        if (!IsListEmpty (&MiMessageInfoListHead)) {

            Message = (PVOID)RemoveHeadList(&MiMessageInfoListHead);
            MiMessageCount -= 1;

            if (!IsListEmpty (&MiMessageInfoListHead)) {

                //
                // The list still contains entries so undo the event autoreset.
                //

                KeSetEvent (&MiMessageEvent, 0, FALSE);
            }
        }

        ExReleaseSpinLock (&MiMessageLock, OldIrql);
    }

    return Message;
}

#endif

#define CONSTANT_UNICODE_STRING(s)   { sizeof( s ) - sizeof( WCHAR ), sizeof( s ), s }

LOGICAL
MiInitializeMemoryEvents (
    VOID
    )
{
    KIRQL OldIrql;
    NTSTATUS Status;
    UNICODE_STRING LowMem = CONSTANT_UNICODE_STRING(L"\\KernelObjects\\LowMemoryCondition");
    UNICODE_STRING HighMem = CONSTANT_UNICODE_STRING(L"\\KernelObjects\\HighMemoryCondition");

    //
    // The thresholds may be set in the registry, if so, they are interpreted
    // in megabytes so convert them to pages now.
    //
    // If the user modifies the registry to introduce his own values, don't
    // bother error checking them as they can't hurt the system regardless (bad
    // values just may result in events not getting signaled or staying
    // signaled when they shouldn't, but that's not fatal).
    //

    if (MmLowMemoryThreshold != 0) {
        MmLowMemoryThreshold *= ((1024 * 1024) / PAGE_SIZE);
    }
    else {

        //
        // Scale the threshold so on servers the low threshold is
        // approximately 32MB per 4GB, capping it at 64MB.
        //

        MmLowMemoryThreshold = MmPlentyFreePages;

        if (MmNumberOfPhysicalPages > 0x40000) {
            MmLowMemoryThreshold = (32 * 1024 * 1024) / PAGE_SIZE;
            MmLowMemoryThreshold += ((MmNumberOfPhysicalPages - 0x40000) >> 7);
        }
        else if (MmNumberOfPhysicalPages > 0x8000) {
            MmLowMemoryThreshold += ((MmNumberOfPhysicalPages - 0x8000) >> 5);
        }

        if (MmLowMemoryThreshold > (64 * 1024 * 1024) / PAGE_SIZE) {
            MmLowMemoryThreshold = (64 * 1024 * 1024) / PAGE_SIZE;
        }
    }

    if (MmHighMemoryThreshold != 0) {
        MmHighMemoryThreshold *= ((1024 * 1024) / PAGE_SIZE);
    }
    else {
        MmHighMemoryThreshold = 3 * MmLowMemoryThreshold;
        ASSERT (MmHighMemoryThreshold > MmLowMemoryThreshold);
    }

    if (MmHighMemoryThreshold < MmLowMemoryThreshold) {
        MmHighMemoryThreshold = MmLowMemoryThreshold;
    }

    Status = MiCreateMemoryEvent (&LowMem, &MiLowMemoryEvent);

    if (!NT_SUCCESS (Status)) {
#if DBG
        DbgPrint ("MM: Memory event initialization failed %x\n", Status);
#endif
        return FALSE;
    }

    Status = MiCreateMemoryEvent (&HighMem, &MiHighMemoryEvent);

    if (!NT_SUCCESS (Status)) {
#if DBG
        DbgPrint ("MM: Memory event initialization failed %x\n", Status);
#endif
        return FALSE;
    }

    //
    // Initialize the event values.
    //

    LOCK_PFN (OldIrql);

    MiNotifyMemoryEvents ();

    UNLOCK_PFN (OldIrql);

    return TRUE;
}

extern POBJECT_TYPE ExEventObjectType;

NTSTATUS
MiCreateMemoryEvent (
    IN PUNICODE_STRING EventName,
    OUT PKEVENT *Event
    )
{
    PACL Dacl;
    HANDLE EventHandle;
    ULONG DaclLength;
    NTSTATUS Status;
    OBJECT_ATTRIBUTES ObjectAttributes;
    SECURITY_DESCRIPTOR SecurityDescriptor;

    Status = RtlCreateSecurityDescriptor (&SecurityDescriptor,
                                          SECURITY_DESCRIPTOR_REVISION);

    if (!NT_SUCCESS (Status)) {
        return Status;
    }

    DaclLength = sizeof (ACL) + sizeof (ACCESS_ALLOWED_ACE) * 3 +
                 RtlLengthSid (SeLocalSystemSid) +
                 RtlLengthSid (SeAliasAdminsSid) +
                 RtlLengthSid (SeWorldSid);

    Dacl = ExAllocatePoolWithTag (PagedPool, DaclLength, 'lcaD');

    if (Dacl == NULL) {
        return STATUS_INSUFFICIENT_RESOURCES;
    }

    Status = RtlCreateAcl (Dacl, DaclLength, ACL_REVISION);

    if (!NT_SUCCESS (Status)) {
        ExFreePool (Dacl);
        return Status;
    }

    Status = RtlAddAccessAllowedAce (Dacl,
                                     ACL_REVISION,
                                     EVENT_ALL_ACCESS,
                                     SeAliasAdminsSid);

    if (!NT_SUCCESS (Status)) {
        ExFreePool (Dacl);
        return Status;
    }

    Status = RtlAddAccessAllowedAce (Dacl,
                                     ACL_REVISION,
                                     EVENT_ALL_ACCESS,
                                     SeLocalSystemSid);

    if (!NT_SUCCESS (Status)) {
        ExFreePool (Dacl);
        return Status;
    }

    Status = RtlAddAccessAllowedAce (Dacl,
                                     ACL_REVISION,
                                     SYNCHRONIZE|EVENT_QUERY_STATE|READ_CONTROL,
                                     SeWorldSid);

    if (!NT_SUCCESS (Status)) {
        ExFreePool (Dacl);
        return Status;
    }
  
    Status = RtlSetDaclSecurityDescriptor (&SecurityDescriptor,
                                           TRUE,
                                           Dacl,
                                           FALSE);

    if (!NT_SUCCESS (Status)) {
        ExFreePool (Dacl);
        return Status;
    }
  
    InitializeObjectAttributes (&ObjectAttributes,
                                EventName,
                                OBJ_KERNEL_HANDLE | OBJ_PERMANENT,
                                NULL,
                                &SecurityDescriptor);

    Status = ZwCreateEvent (&EventHandle,
                            EVENT_ALL_ACCESS,
                            &ObjectAttributes,
                            NotificationEvent,
                            FALSE);

    ExFreePool (Dacl);

    if (NT_SUCCESS (Status)) {
        Status = ObReferenceObjectByHandle (EventHandle,
                                            EVENT_MODIFY_STATE,
                                            ExEventObjectType,
                                            KernelMode,
                                            (PVOID *)Event,
                                            NULL);
    }

    ZwClose (EventHandle);

    return Status;
}

VOID
MiNotifyMemoryEvents (
    VOID
    )
// PFN lock is held.
{
    if (MmAvailablePages <= MmLowMemoryThreshold) {

        if (KeReadStateEvent (MiHighMemoryEvent) != 0) {
            KeClearEvent (MiHighMemoryEvent);
        }

        if (KeReadStateEvent (MiLowMemoryEvent) == 0) {
            KeSetEvent (MiLowMemoryEvent, 0, FALSE);
        }
    }
    else if (MmAvailablePages < MmHighMemoryThreshold) {

        //
        // Gray zone, make sure both events are cleared.
        //

        if (KeReadStateEvent (MiHighMemoryEvent) != 0) {
            KeClearEvent (MiHighMemoryEvent);
        }

        if (KeReadStateEvent (MiLowMemoryEvent) != 0) {
            KeClearEvent (MiLowMemoryEvent);
        }
    }
    else {
        if (KeReadStateEvent (MiHighMemoryEvent) == 0) {
            KeSetEvent (MiHighMemoryEvent, 0, FALSE);
        }

        if (KeReadStateEvent (MiLowMemoryEvent) != 0) {
            KeClearEvent (MiLowMemoryEvent);
        }
    }

    return;
}

VOID
MiInitializeCacheOverrides (
    VOID
    )
{
#if defined (_WIN64)

    ULONG NumberOfBytes;
    NTSTATUS Status;
    HAL_PLATFORM_INFORMATION Information;

    //
    // Gather platform information from the HAL.
    //

    Status = HalQuerySystemInformation (HalPlatformInformation, 
                                        sizeof (Information),
                                        &Information,
                                        &NumberOfBytes);

    if (!NT_SUCCESS (Status)) {
        return;
    }

    //
    // Apply mapping modifications based on platform information flags.
    //
    // It would be better if the platform returned what the new cachetype
    // should be.
    //

    if (Information.PlatformFlags & HAL_PLATFORM_DISABLE_UC_MAIN_MEMORY) {
          MI_SET_CACHETYPE_TRANSLATION (MmNonCached, 0, MiCached);
    }
#endif

    return;
}