NT4/private/ntos/mm/mminit.c
2020-09-30 17:12:29 +02:00

1981 lines
55 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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
Revision History:
--*/
#include "mi.h"
MMPTE MmSharedUserDataPte;
extern ULONG MmPagedPoolCommit;
extern ULONG MmHeapSegmentReserve;
extern ULONG MmHeapSegmentCommit;
extern ULONG MmHeapDeCommitTotalFreeThreshold;
extern ULONG MmHeapDeCommitFreeBlockThreshold;
extern MMINPAGE_SUPPORT_LIST MmInPageSupportList;
extern MMEVENT_COUNT_LIST MmEventCountList;
extern KMUTANT MmSystemLoadLock;
extern ULONG MmSystemPtesStart[MaximumPtePoolTypes];
ULONG MmSubsectionBase;
ULONG MmSubsectionTopPage;
ULONG MmDataClusterSize;
ULONG MmCodeClusterSize;
ULONG MmResidentAvailableAtInit;
KEVENT MmImageMappingPteEvent;
PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock;
#if DBG
PRTL_EVENT_ID_INFO MiAllocVmEventId;
PRTL_EVENT_ID_INFO MiFreeVmEventId;
#endif // DBG
VOID
MiEnablePagingTheExecutive(
VOID
);
VOID
MiEnablePagingOfDriverAtInit (
IN PMMPTE PointerPte,
IN PMMPTE LastPte
);
VOID
MiBuildPagedPool (
);
VOID
MiMergeMemoryLimit (
IN OUT PPHYSICAL_MEMORY_DESCRIPTOR Memory,
IN ULONG StartPage,
IN ULONG NoPages
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,MmInitSystem)
#pragma alloc_text(INIT,MmInitializeMemoryLimits)
#pragma alloc_text(INIT,MiMergeMemoryLimit)
#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(PAGELK,MiFreeInitializationCode)
#endif
#define MM_MAX_LOADER_BLOCKS 20
//
// The following constants are base on the number PAGES not the
// memory size. For convience 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 (512 * 1024)
extern ULONG MmMaximumWorkingSetSize;
ULONG MmSystemPageDirectory;
PMMPTE MmSystemPagePtes;
ULONG MmTotalSystemCodePages;
MM_SYSTEMSIZE MmSystemSize;
ULONG MmLargeSystemCache;
ULONG MmProductType;
LIST_ENTRY MmLoadedUserImageList;
BOOLEAN
MmInitSystem (
IN ULONG Phase,
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PPHYSICAL_MEMORY_DESCRIPTOR PhysicalMemoryBlock
)
/*++
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.
LoadBlock - Supplies a pointer the ssystem loader block.
Return Value:
Returns TRUE if the initialization was successful.
Environment:
Kernel Mode Only. System initialization.
--*/
{
HANDLE ThreadHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
PMMPTE PointerPte;
PMMPTE PointerPde;
PMMPTE StartPde;
PMMPTE StartingPte;
PMMPTE EndPde;
PMMPFN Pfn1;
ULONG i, j;
ULONG PageFrameIndex;
MMPTE TempPte;
KIRQL OldIrql;
BOOLEAN IncludeType[LoaderMaximum];
ULONG MemoryAlloc[(sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
sizeof(PHYSICAL_MEMORY_RUN)*MAX_PHYSICAL_MEMORY_FRAGMENTS) /
sizeof(ULONG)];
PPHYSICAL_MEMORY_DESCRIPTOR Memory;
//
// Make sure structure alignment is okay.
//
if (Phase == 0) {
MmThrottleTop = 450;
MmThrottleBottom = 127;
#if DBG
//
// A few sanity checks to ensure things are as they should be.
//
if (sizeof(MMPFN) != 24) {
DbgPrint("pfn element size is not 24\n");
}
if ((sizeof(MMWSL) % 8) != 0) {
DbgPrint("working set list is not a quadword sized structure\n");
}
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;
i = MiProtoAddressForPte (PointerPte);
TempPte.u.Long = i;
PointerPde = MiPteToProto(&TempPte);
if (PointerPte != PointerPde) {
DbgPrint("unable to map start of paged pool as prototype pte %lx %lx\n",
PointerPde, PointerPte);
}
PointerPte =
(PMMPTE)((ULONG)MM_NONPAGED_POOL_END & ~((1 << PTE_SHIFT) - 1));
i = MiProtoAddressForPte (PointerPte);
TempPte.u.Long = i;
PointerPde = MiPteToProto(&TempPte);
if (PointerPte != PointerPde) {
DbgPrint("unable to map end of nonpaged pool as prototype pte %lx %lx\n",
PointerPde, PointerPte);
}
PointerPte = (PMMPTE)(((ULONG)NON_PAGED_SYSTEM_END - 0x37000 + PAGE_SIZE-1) & ~(PAGE_SIZE-1));
for (j = 0; j < 20; j++) {
i = MiProtoAddressForPte (PointerPte);
TempPte.u.Long = i;
PointerPde = MiPteToProto(&TempPte);
if (PointerPte != PointerPde) {
DbgPrint("unable to map end of nonpaged pool as prototype pte %lx %lx\n",
PointerPde, PointerPte);
}
PointerPte++;
}
PointerPte = (PMMPTE)(((ULONG)MM_NONPAGED_POOL_END - 0x133448) & ~7);
i = MiGetSubsectionAddressForPte (PointerPte);
TempPte.u.Long = i;
PointerPde = (PMMPTE)MiGetSubsectionAddress(&TempPte);
if (PointerPte != PointerPde) {
DbgPrint("unable to map end of nonpaged pool as section pte %lx %lx\n",
PointerPde, PointerPte);
MiFormatPte(&TempPte);
}
//
// End of sanity checks.
//
#endif //dbg
InitializeListHead( &MmLoadedUserImageList );
MmCriticalSectionTimeout.QuadPart = Int32x32To64(
MmCritsectTimeoutSeconds,
-10000000);
//
// Initialize PFN database mutex and System Address Space creation
// mutex.
//
MmNumberOfColors = MM_MAXIMUM_NUMBER_OF_COLORS;
ExInitializeFastMutex (&MmSectionCommitMutex);
ExInitializeFastMutex (&MmSectionBasedMutex);
KeInitializeMutant (&MmSystemLoadLock, FALSE);
KeInitializeEvent (&MmAvailablePagesEvent, NotificationEvent, TRUE);
KeInitializeEvent (&MmAvailablePagesEventHigh, NotificationEvent, TRUE);
KeInitializeEvent (&MmMappedFileIoComplete, NotificationEvent, FALSE);
KeInitializeEvent (&MmImageMappingPteEvent, NotificationEvent, FALSE);
KeInitializeEvent (&MmZeroingPageEvent, SynchronizationEvent, FALSE);
KeInitializeEvent (&MmCollidedFlushEvent, NotificationEvent, FALSE);
KeInitializeEvent (&MmCollidedLockEvent, NotificationEvent, FALSE);
InitializeListHead (&MmWorkingSetExpansionHead.ListHead);
InitializeListHead (&MmInPageSupportList.ListHead);
InitializeListHead (&MmEventCountList.ListHead);
MmZeroingPageThreadActive = FALSE;
//
// Compute pyhiscal memory block a yet again
//
Memory = (PPHYSICAL_MEMORY_DESCRIPTOR)&MemoryAlloc;
Memory->NumberOfRuns = MAX_PHYSICAL_MEMORY_FRAGMENTS;
// include all memory types ...
for (i=0; i < LoaderMaximum; i++) {
IncludeType[i] = TRUE;
}
// ... expect these..
IncludeType[LoaderBad] = FALSE;
IncludeType[LoaderFirmwarePermanent] = FALSE;
IncludeType[LoaderSpecialMemory] = FALSE;
MmInitializeMemoryLimits(LoaderBlock, IncludeType, Memory);
//
// Add all memory runs in PhysicalMemoryBlock to Memory
//
for (i=0; i < PhysicalMemoryBlock->NumberOfRuns; i++) {
MiMergeMemoryLimit (
Memory,
PhysicalMemoryBlock->Run[i].BasePage,
PhysicalMemoryBlock->Run[i].PageCount
);
}
#ifdef MIPS
//
// On mips machines these first two pages of physical memory are
// used for important stuff.
//
Memory->Run[Memory->NumberOfRuns].BasePage = 0;
Memory->Run[Memory->NumberOfRuns].PageCount = 2;
Memory->NumberOfRuns += 1;
Memory->NumberOfPages += 2;
#endif //MIPS
//
// Sort and merge adjacent runs
//
for (i=0; i < Memory->NumberOfRuns; i++) {
for (j=i+1; j < Memory->NumberOfRuns; j++) {
if (Memory->Run[j].BasePage < Memory->Run[i].BasePage) {
// swap runs
PhysicalMemoryBlock->Run[0] = Memory->Run[j];
Memory->Run[j] = Memory->Run[i];
Memory->Run[i] = PhysicalMemoryBlock->Run[0];
}
if (Memory->Run[i].BasePage + Memory->Run[i].PageCount ==
Memory->Run[j].BasePage) {
// merge runs
Memory->NumberOfRuns -= 1;
Memory->Run[i].PageCount += Memory->Run[j].PageCount;
Memory->Run[j] = Memory->Run[Memory->NumberOfRuns];
i -= 1;
break;
}
}
}
if (MmNumberOfSystemPtes == 0) {
if (Memory->NumberOfPages < MM_MEDIUM_SYSTEM) {
MmNumberOfSystemPtes = MM_MINIMUM_SYSTEM_PTES;
} else {
MmNumberOfSystemPtes = MM_DEFAULT_SYSTEM_PTES;
if (Memory->NumberOfPages > 8192) {
MmNumberOfSystemPtes += MmNumberOfSystemPtes;
}
}
}
if (MmNumberOfSystemPtes > MM_MAXIMUM_SYSTEM_PTES) {
MmNumberOfSystemPtes = MM_MAXIMUM_SYSTEM_PTES;
}
if (MmNumberOfSystemPtes < MM_MINIMUM_SYSTEM_PTES) {
MmNumberOfSystemPtes = MM_MINIMUM_SYSTEM_PTES;
}
if ( !MmHeapSegmentReserve ) {
MmHeapSegmentReserve = 1024 * 1024;
}
if ( !MmHeapSegmentCommit ) {
MmHeapSegmentCommit = PAGE_SIZE * 2;
}
if ( !MmHeapDeCommitTotalFreeThreshold ) {
MmHeapDeCommitTotalFreeThreshold = 64 * 1024;
}
if ( !MmHeapDeCommitFreeBlockThreshold ) {
MmHeapDeCommitFreeBlockThreshold = PAGE_SIZE;
}
#if DBG
if (MmSpecialPoolTag != 0) {
MmNumberOfSystemPtes += 25000;
}
#endif //DBG
//
// Initialize the machine dependent portion of the hardware.
//
ExInitializeResource (&MmSystemWsLock);
MiInitMachineDependent (LoaderBlock);
j = (sizeof(PHYSICAL_MEMORY_DESCRIPTOR) +
(sizeof(PHYSICAL_MEMORY_RUN) *
(Memory->NumberOfRuns - 1)));
MmPhysicalMemoryBlock = ExAllocatePoolWithTag (NonPagedPoolMustSucceed,
j,
' mM');
RtlCopyMemory (MmPhysicalMemoryBlock, Memory, j);
//
// 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
//
MmReadClusterSize = 7;
if (MmNumberOfPhysicalPages <= MM_SMALL_SYSTEM ) {
MmSystemSize = MmSmallSystem;
MmMaximumDeadKernelStacks = 0;
MmModifiedPageMinimum = 40;
MmModifiedPageMaximum = 100;
MmDataClusterSize = 0;
MmCodeClusterSize = 1;
MmReadClusterSize = 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;
} else {
MmSystemSize = MmMediumSystem;
MmMaximumDeadKernelStacks = 5;
MmModifiedPageMinimum = 150;
MmModifiedPageMaximum = 300;
MmSystemCacheWsMinimum += 400;
MmSystemCacheWsMaximum += 800;
MmDataClusterSize = 3;
MmCodeClusterSize = 7;
}
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;
}
//
// 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;
}
MiAdjustWorkingSetManagerParameters((BOOLEAN)(MmProductType == 0 ? TRUE : FALSE));
//
// Set the ResidentAvailablePages to the number of available
// pages minum the fluid value.
//
MmResidentAvailablePages = MmAvailablePages - MM_FLUID_PHYSICAL_PAGES;
//
// Subtract off the size of the system cache working set.
//
MmResidentAvailablePages -= MmSystemCacheWsMinimum;
MmResidentAvailableAtInit = MmResidentAvailablePages;
if ((LONG)MmResidentAvailablePages < 0) {
#if DBG
DbgPrint("system cache working set too big\n");
#endif
return FALSE;
}
//
// Initialize spin lock for charging and releasing page file
// commitment.
//
KeInitializeSpinLock (&MmChargeCommitmentLock);
//
// Initialize spin lock for allowing working set expansion.
//
KeInitializeSpinLock (&MmExpansionLock);
ExInitializeFastMutex (&MmPageFileCreationLock);
//
// Initialize resource for extending sections.
//
ExInitializeResource (&MmSectionExtendResource);
ExInitializeResource (&MmSectionExtendSetResource);
//
// Build the system cache structures.
//
StartPde = MiGetPdeAddress (MmSystemCacheWorkingSetList);
PointerPte = MiGetPteAddress (MmSystemCacheWorkingSetList);
ASSERT ((StartPde + 1) == MiGetPdeAddress (MmSystemCacheStart));
//
// 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 = ((128*1024*1024) >> PAGE_SHIFT) +
((i - 4) * ((64*1024*1024) >> PAGE_SHIFT));
if (MmSizeOfSystemCacheInPages > MM_MAXIMUM_SYSTEM_CACHE_SIZE) {
MmSizeOfSystemCacheInPages = MM_MAXIMUM_SYSTEM_CACHE_SIZE;
}
}
MmSystemCacheEnd = (PVOID)(((ULONG)MmSystemCacheStart +
MmSizeOfSystemCacheInPages * PAGE_SIZE) - 1);
EndPde = MiGetPdeAddress(MmSystemCacheEnd);
TempPte = ValidKernelPte;
LOCK_PFN (OldIrql);
while (StartPde <= EndPde) {
ASSERT (StartPde->u.Hard.Valid == 0);
//
// Map in a page directory page.
//
PageFrameIndex = MiRemoveAnyPage(
MI_GET_PAGE_COLOR_FROM_PTE (StartPde));
TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
*StartPde = TempPte;
Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
Pfn1->PteFrame =
MiGetPdeAddress(PDE_BASE)->u.Hard.PageFrameNumber;
Pfn1->PteAddress = StartPde;
Pfn1->u2.ShareCount += 1;
Pfn1->u3.e2.ReferenceCount = 1;
Pfn1->u3.e1.PageLocation = ActiveAndValid;
Pfn1->OriginalPte.u.Long = 0;
RtlFillMemoryUlong (PointerPte,
PAGE_SIZE,
ZeroKernelPte.u.Long);
StartPde += 1;
PointerPte += PTE_PER_PAGE;
}
UNLOCK_PFN (OldIrql);
//
// Initialize the system cache.
//
if (MmLargeSystemCache != 0) {
if ((MmAvailablePages >
MmSystemCacheWsMaximum + ((6*1024*1024) >> PAGE_SHIFT))) {
MmSystemCacheWsMaximum =
MmAvailablePages - ((4*1024*1024) >> PAGE_SHIFT);
MmMoreThanEnoughFreePages = 256;
}
}
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;
}
}
if (!MiInitializeSystemCache (MmSizeOfSystemCacheInPages,
MmSystemCacheWsMinimum,
MmSystemCacheWsMaximum
)) {
return FALSE;
}
//
// Set the commit page limit to four times the number of available
// pages. This value is updated as paging files are created.
//
MmTotalCommitLimit = MmAvailablePages << 2;
MmAttemptForCantExtend.Segment = NULL;
MmAttemptForCantExtend.RequestedExpansionSize = 1;
MmAttemptForCantExtend.ActualExpansion = 1;
MmAttemptForCantExtend.InProgress = FALSE;
KeInitializeEvent (&MmAttemptForCantExtend.Event,
NotificationEvent,
FALSE);
if (MmOverCommit == 0) {
// If this value was not set via the regisistry, set the
// over commit value to the number of available pages
// minus 1024 pages (4mb with 4k pages).
//
if (MmAvailablePages > 1024) {
MmOverCommit = MmAvailablePages - 1024;
}
}
//
// Set maximum working set size to 512 pages less total available
// memory. 2mb on machine with 4k pages.
//
MmMaximumWorkingSetSize = 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 ();
//
// Add more system PTEs if large memory system.
//
if (MmNumberOfPhysicalPages > ((128*1024*1024) >> PAGE_SHIFT)) {
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);
PageFrameIndex = MiRemoveAnyPage (
MI_GET_PAGE_COLOR_FROM_PTE (PointerPde));
TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
*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);
MmSystemPtesStart[SystemPteSpace] = (ULONG)StartingPte;
MmNonPagedSystemStart = MiGetVirtualAddressMappedByPte (StartingPte);
MmNumberOfSystemPtes += j;
MiReleaseSystemPtes (StartingPte, j, SystemPteSpace);
}
}
#if DBG
if (MmDebug & MM_DBG_DUMP_BOOT_PTES) {
MiDumpValidAddresses ();
MiDumpPfn ();
}
#endif
#if DBG
MiAllocVmEventId = RtlCreateEventId( NULL,
0,
"AllocVM",
5,
RTL_EVENT_ULONG_PARAM, "Addr", 0,
RTL_EVENT_ULONG_PARAM, "Size", 0,
RTL_EVENT_FLAGS_PARAM, "", 3,
MEM_RESERVE, "Reserve",
MEM_COMMIT, "Commit",
MEM_TOP_DOWN, "TopDown",
RTL_EVENT_ENUM_PARAM, "", 8,
PAGE_NOACCESS, "NoAccess",
PAGE_READONLY, "ReadOnly",
PAGE_READWRITE, "ReadWrite",
PAGE_WRITECOPY, "CopyOnWrite",
PAGE_EXECUTE, "Execute",
PAGE_EXECUTE_READ, "ExecuteRead",
PAGE_EXECUTE_READWRITE, "ExecuteReadWrite",
PAGE_EXECUTE_WRITECOPY, "ExecuteCopyOnWrite",
RTL_EVENT_FLAGS_PARAM, "", 2,
PAGE_GUARD, "Guard",
PAGE_NOCACHE, "NoCache"
);
MiFreeVmEventId = RtlCreateEventId( NULL,
0,
"FreeVM",
3,
RTL_EVENT_ULONG_PARAM, "Addr", 0,
RTL_EVENT_ULONG_PARAM, "Size", 0,
RTL_EVENT_FLAGS_PARAM, "", 2,
MEM_RELEASE, "Release",
MEM_DECOMMIT, "DeCommit"
);
#endif // DBG
return TRUE;
}
if (Phase == 1) {
#if DBG
MmDebug |= MM_DBG_CHECK_PFN_LOCK;
#endif
#ifdef _X86_
MiInitMachineDependent (LoaderBlock);
#endif
if (!MiSectionInitialization ()) {
return FALSE;
}
#if defined(MM_SHARED_USER_DATA_VA)
//
// Create double mapped page between kernel and user mode.
//
PointerPte = MiGetPteAddress(KI_USER_SHARED_DATA);
ASSERT (PointerPte->u.Hard.Valid == 1);
PageFrameIndex = PointerPte->u.Hard.PageFrameNumber;
MI_MAKE_VALID_PTE (MmSharedUserDataPte,
PageFrameIndex,
MM_READONLY,
PointerPte);
Pfn1 = MI_PFN_ELEMENT (PageFrameIndex);
Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE;
#endif
//
// Set up system wide lock pages limit.
//
MmLockPagesLimit = MmLockLimitInBytes >> PAGE_SHIFT;
if (MmLockPagesLimit < MM_DEFAULT_IO_LOCK_LIMIT) {
MmLockPagesLimit = MM_DEFAULT_IO_LOCK_LIMIT;
}
if ((MmLockPagesLimit + ((7 * 1024*1024) / PAGE_SIZE)) > MmAvailablePages) {
MmLockPagesLimit = MmAvailablePages - ((7 * 1024*1024) / PAGE_SIZE);
if ((LONG)MmLockPagesLimit < (MM_DEFAULT_IO_LOCK_LIMIT / PAGE_SIZE)) {
MmLockPagesLimit = MM_DEFAULT_IO_LOCK_LIMIT / PAGE_SIZE;
}
}
MmPagingFileCreated = ExAllocatePoolWithTag (NonPagedPool,
sizeof(KEVENT),
'fPmM');
if (MmPagingFileCreated == NULL) {
//
// Pool allocation failed, return FALSE.
//
return FALSE;
}
KeInitializeEvent (MmPagingFileCreated, NotificationEvent, FALSE);
//
// 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);
//
// 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);
MiEnablePagingTheExecutive();
return TRUE;
}
return FALSE;
}
VOID
MmInitializeMemoryLimits (
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
IN PBOOLEAN IncludeType,
OUT PPHYSICAL_MEMORY_DESCRIPTOR Memory
)
/*++
Routine Description:
This function walks through the loader block's memory
description list and builds a list of contiguous physical
memory blocks of the desired types.
Arguments:
LoadBlock - Supplies a pointer the ssystem loader block.
IncludeType - Array of BOOLEANS size LoaderMaximum.
TRUE means include this type of memory in return.
Memory - Returns the physical memory blocks.
Return Value:
None.
Environment:
Kernel Mode Only. System initialization.
--*/
{
PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
PLIST_ENTRY NextMd;
ULONG i;
ULONG LowestFound;
ULONG Found;
ULONG Merged;
ULONG NextPage;
ULONG TotalPages = 0;
//
// Walk through the memory descriptors and build physical memory list.
//
LowestFound = 0;
Memory->Run[0].BasePage = 0xffffffff;
NextPage = 0xffffffff;
Memory->Run[0].PageCount = 0;
i = 0;
do {
Merged = FALSE;
Found = FALSE;
NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
MemoryDescriptor = CONTAINING_RECORD(NextMd,
MEMORY_ALLOCATION_DESCRIPTOR,
ListEntry);
if (MemoryDescriptor->MemoryType < LoaderMaximum &&
IncludeType [MemoryDescriptor->MemoryType] ) {
//
// Try to merge runs.
//
if (MemoryDescriptor->BasePage == NextPage) {
ASSERT (MemoryDescriptor->PageCount != 0);
Memory->Run[i - 1].PageCount += MemoryDescriptor->PageCount;
NextPage += MemoryDescriptor->PageCount;
TotalPages += MemoryDescriptor->PageCount;
Merged = TRUE;
Found = TRUE;
break;
}
if (MemoryDescriptor->BasePage >= LowestFound) {
if (Memory->Run[i].BasePage > MemoryDescriptor->BasePage) {
Memory->Run[i].BasePage = MemoryDescriptor->BasePage;
Memory->Run[i].PageCount = MemoryDescriptor->PageCount;
}
Found = TRUE;
}
}
NextMd = MemoryDescriptor->ListEntry.Flink;
}
if (!Merged && Found) {
NextPage = Memory->Run[i].BasePage + Memory->Run[i].PageCount;
TotalPages += Memory->Run[i].PageCount;
i += 1;
}
Memory->Run[i].BasePage = 0xffffffff;
LowestFound = NextPage;
} while (Found);
ASSERT (i <= Memory->NumberOfRuns);
Memory->NumberOfRuns = i;
Memory->NumberOfPages = TotalPages;
return;
}
VOID
MiMergeMemoryLimit (
IN OUT PPHYSICAL_MEMORY_DESCRIPTOR Memory,
IN ULONG StartPage,
IN ULONG NoPages
)
/*++
Routine Description:
This function ensures the passed range is in the passed in Memory
block adding any new data as needed.
The passed memory block is assumed to be at least
MAX_PHYSICAL_MEMORY_FRAGMENTS large
Arguments:
Memory - Memory block to verify run is present in
StartPage - First page of run
NoPages - Number of pages in run
Return Value:
None.
Environment:
Kernel Mode Only. System initialization.
--*/
{
ULONG EndPage, sp, ep, i;
EndPage = StartPage + NoPages;
//
// Clip range to area which is not already described
//
for (i=0; i < Memory->NumberOfRuns; i++) {
sp = Memory->Run[i].BasePage;
ep = sp + Memory->Run[i].PageCount;
if (sp < StartPage) {
if (ep > StartPage && ep < EndPage) {
// bump begining page of the target area
StartPage = ep;
}
if (ep > EndPage) {
//
// Target area is contained totally within this
// descriptor. This range is fully accounted for.
//
StartPage = EndPage;
}
} else {
// sp >= StartPage
if (sp < EndPage) {
if (ep < EndPage) {
//
// This descriptor is totally within the target area -
// check the area on either side of this desctipor
//
MiMergeMemoryLimit (Memory, StartPage, sp - StartPage);
StartPage = ep;
} else {
// clip the ending page of the target area
EndPage = sp;
}
}
}
//
// Anything left of target area?
//
if (StartPage == EndPage) {
return ;
}
} // next descrtiptor
//
// The range StartPage - EndPage is a missing. Add it.
//
if (Memory->NumberOfRuns == MAX_PHYSICAL_MEMORY_FRAGMENTS) {
return ;
}
Memory->Run[Memory->NumberOfRuns].BasePage = StartPage;
Memory->Run[Memory->NumberOfRuns].PageCount = EndPage - StartPage;
Memory->NumberOfPages += EndPage - StartPage;
Memory->NumberOfRuns += 1;
}
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:
LoadBlock - Supplies a pointer the ssystem loader block.
Return Value:
None.
Environment:
Kernel Mode Only. System initialization.
--*/
{
PLIST_ENTRY NextMd;
PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor;
MEMORY_ALLOCATION_DESCRIPTOR SavedDescriptor[MM_MAX_LOADER_BLOCKS];
ULONG i;
ULONG NextPhysicalPage;
PMMPFN Pfn1;
LONG BlockNumber = -1;
KIRQL OldIrql;
//
//
// 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.
//
BlockNumber += 1;
if (BlockNumber >= MM_MAX_LOADER_BLOCKS) {
KeBugCheck (MEMORY_MANAGEMENT);
}
SavedDescriptor[BlockNumber] = *MemoryDescriptor;
break;
default:
break;
}
NextMd = MemoryDescriptor->ListEntry.Flink;
}
LOCK_PFN (OldIrql);
while (BlockNumber >= 0) {
i = SavedDescriptor[BlockNumber].PageCount;
NextPhysicalPage = SavedDescriptor[BlockNumber].BasePage;
Pfn1 = MI_PFN_ELEMENT (NextPhysicalPage);
while (i != 0) {
if (Pfn1->u3.e2.ReferenceCount == 0) {
if (Pfn1->u1.Flink == 0) {
//
// Set the PTE address to the phyiscal page for
// virtual address alignment checking.
//
Pfn1->PteAddress =
(PMMPTE)(NextPhysicalPage << PTE_SHIFT);
MiInsertPageInList (MmPageLocationList[FreePageList],
NextPhysicalPage);
}
} else {
if (NextPhysicalPage != 0) {
//
// Remove PTE and insert into the free list. If it is
// a phyical 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++;
i -= 1;
NextPhysicalPage += 1;
}
BlockNumber -= 1;
}
KeFlushEntireTb (TRUE, TRUE);
UNLOCK_PFN (OldIrql);
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.
--*/
{
ULONG Size;
PMMPTE PointerPte;
PMMPTE PointerPde;
MMPTE TempPte;
PMMPFN Pfn1;
ULONG PageFrameIndex;
KIRQL OldIrql;
//
// Double map system page directory page.
//
MmSystemPageDirectory = MiGetPdeAddress(PDE_BASE)->u.Hard.PageFrameNumber;
MmSystemPagePtes = (PMMPTE)MiMapPageInHyperSpace (MmSystemPageDirectory,
&OldIrql);
MiUnmapPageInHyperSpace (OldIrql);
if (!MI_IS_PHYSICAL_ADDRESS(MmSystemPagePtes)) {
//
// Was not mapped physically, map it virtually in system space.
//
PointerPte = MiReserveSystemPtes (
1,
SystemPteSpace,
MM_COLOR_ALIGNMENT,
((ULONG)PDE_BASE & MM_COLOR_MASK_VIRTUAL),
TRUE);
*PointerPte = ValidKernelPte;
PointerPte->u.Hard.PageFrameNumber = MmSystemPageDirectory;
MmSystemPagePtes = (PMMPTE)MiGetVirtualAddressMappedByPte (PointerPte);
}
//
// Allocate the prototype PTEs for paged pool.
//
//
// A size of 0 means size the pool based on physical memory.
//
if (MmSizeOfPagedPoolInBytes == 0) {
MmSizeOfPagedPoolInBytes = 2 * MmMaximumNonPagedPoolInBytes;
}
if (MmIsThisAnNtAsSystem()) {
if (MmSizeOfPagedPoolInBytes < MM_MINIMUM_PAGED_POOL_NTAS) {
MmSizeOfPagedPoolInBytes = MM_MINIMUM_PAGED_POOL_NTAS;
}
}
if (MmSizeOfPagedPoolInBytes >
(ULONG)((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;
}
Size = (Size + (PTE_PER_PAGE - 1)) / PTE_PER_PAGE;
MmSizeOfPagedPoolInBytes = Size * PAGE_SIZE * PTE_PER_PAGE;
ASSERT ((MmSizeOfPagedPoolInBytes + (PCHAR)MmPagedPoolStart) <=
(PCHAR)MmNonPagedSystemStart);
//
// Set size to the number of pages in the pool.
//
Size = Size * PTE_PER_PAGE;
MmPagedPoolEnd = (PVOID)(((PUCHAR)MmPagedPoolStart +
MmSizeOfPagedPoolInBytes) - 1);
MmPageAlignedPoolBase[PagedPool] = MmPagedPoolStart;
//
// Build page table page for paged pool.
//
PointerPde = MiGetPdeAddress (MmPagedPoolStart);
MmPagedPoolBasePde = PointerPde;
PointerPte = MiGetPteAddress (MmPagedPoolStart);
MmFirstPteForPagedPool = PointerPte;
MmLastPteForPagedPool = MiGetPteAddress (MmPagedPoolEnd);
RtlFillMemoryUlong (PointerPde,
sizeof(MMPTE) *
(1 + MiGetPdeAddress (MmPagedPoolEnd) - PointerPde),
MM_KERNEL_NOACCESS_PTE);
TempPte = ValidKernelPde;
LOCK_PFN (OldIrql);
//
// Map in a page table page.
//
PageFrameIndex = MiRemoveAnyPage(
MI_GET_PAGE_COLOR_FROM_PTE (PointerPde));
TempPte.u.Hard.PageFrameNumber = PageFrameIndex;
*PointerPde = TempPte;
Pfn1 = MI_PFN_ELEMENT(PageFrameIndex);
Pfn1->PteFrame = MmSystemPageDirectory;
Pfn1->PteAddress = PointerPde;
Pfn1->u2.ShareCount = 1;
Pfn1->u3.e2.ReferenceCount = 1;
Pfn1->u3.e1.PageLocation = ActiveAndValid;
Pfn1->OriginalPte.u.Long = 0;
RtlFillMemoryUlong (PointerPte, PAGE_SIZE, MM_KERNEL_DEMAND_ZERO_PTE);
UNLOCK_PFN (OldIrql);
MmNextPteForPagedPoolExpansion = PointerPde + 1;
//
// Build bitmaps for paged pool.
//
MiCreateBitMap (&MmPagedPoolAllocationMap, Size, NonPagedPool);
RtlSetAllBits (MmPagedPoolAllocationMap);
//
// Indicate first page worth of PTEs are available.
//
RtlClearBits (MmPagedPoolAllocationMap, 0, PTE_PER_PAGE);
MiCreateBitMap (&MmEndOfPagedPoolBitmap, Size, NonPagedPool);
RtlClearAllBits (MmEndOfPagedPoolBitmap);
//
// Initialize paged pool.
//
InitializePool (PagedPool, 0L);
//
// Allow mapping of views into system space.
//
MiInitializeSystemSpaceMap ();
//
// Set up the modified page writer.
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.
--*/
{
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
PVOID CurrentBase;
PVOID InitStart;
PVOID InitEnd;
PLIST_ENTRY Next;
PIMAGE_NT_HEADERS NtHeader;
PIMAGE_SECTION_HEADER SectionTableEntry;
LONG i;
ULONG ValidPages;
PMMPTE PointerPte;
KIRQL OldIrql;
PVOID MiFindInitializationCodeAddress = MmGetProcedureAddress((PVOID)&MiFindInitializationCode);
*StartVa = NULL;
//
// Walk through the loader blocks looking for the base which
// contains this routine.
//
KeEnterCriticalRegion();
ExAcquireResourceExclusive (&PsLoadedModuleResource, TRUE);
Next = PsLoadedModuleList.Flink;
while ( Next != &PsLoadedModuleList ) {
LdrDataTableEntry = CONTAINING_RECORD( Next,
LDR_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)((ULONG)NtHeader +
sizeof(ULONG) +
sizeof(IMAGE_FILE_HEADER) +
NtHeader->FileHeader.SizeOfOptionalHeader);
//
// From the image header, locate the section named 'INIT'.
//
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 //DBG
if (*(PULONG)SectionTableEntry->Name == 'TINI') {
InitStart = (PVOID)((PCHAR)CurrentBase + SectionTableEntry->VirtualAddress);
InitEnd = (PVOID)((PCHAR)InitStart + SectionTableEntry->SizeOfRawData - 1);
InitEnd = (PVOID)((PCHAR)PAGE_ALIGN ((ULONG)InitEnd +
(NtHeader->OptionalHeader.SectionAlignment - 1)) - 1);
InitStart = (PVOID)ROUND_TO_PAGES (InitStart);
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!
//
*StartVa = InitStart;
*EndVa = InitEnd;
break;
} else {
//
// See if any more sections are discardable after this
// one.
//
while (i > 1) {
SectionTableEntry += 1;
i -= 1;
if ((SectionTableEntry->Characteristics &
IMAGE_SCN_MEM_DISCARDABLE) != 0) {
//
// Discard this too.
//
InitEnd = (PVOID)(((PCHAR)CurrentBase +
SectionTableEntry->VirtualAddress) +
(SectionTableEntry->SizeOfRawData - 1));
InitEnd = (PVOID)((PCHAR)PAGE_ALIGN ((ULONG)InitEnd +
(NtHeader->OptionalHeader.SectionAlignment - 1)) - 1);
} else {
break;
}
}
if (InitEnd > (PVOID)((PCHAR)CurrentBase +
LdrDataTableEntry->SizeOfImage)) {
InitEnd = (PVOID)(((ULONG)CurrentBase +
(LdrDataTableEntry->SizeOfImage - 1)) |
(PAGE_SIZE - 1));
}
MiFreeInitializationCode (InitStart, InitEnd);
}
}
}
i -= 1;
SectionTableEntry += 1;
}
Next = Next->Flink;
}
ExReleaseResource (&PsLoadedModuleResource);
KeLeaveCriticalRegion();
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;
ULONG PageFrameIndex;
KIRQL OldIrql;
PVOID UnlockHandle;
ULONG ValidPages;
UnlockHandle = MmLockPagableCodeSection((PVOID)MiFreeInitializationCode);
ASSERT(UnlockHandle);
PointerPte = MiGetPteAddress (StartVa);
if (MI_IS_PHYSICAL_ADDRESS(StartVa)) {
LOCK_PFN (OldIrql);
while (StartVa < EndVa) {
//
// On certains 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);
MiInsertPageInList (MmPageLocationList[FreePageList], PageFrameIndex);
StartVa = (PVOID)((PUCHAR)StartVa + PAGE_SIZE);
}
UNLOCK_PFN (OldIrql);
} else {
MiDeleteSystemPagableVm (PointerPte,
1 + MiGetPteAddress (EndVa) -
PointerPte,
MM_ZERO_KERNEL_PTE,
&ValidPages);
}
MmUnlockPagableImageSection(UnlockHandle);
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.
--*/
{
#if defined(_X86_) || defined(_PPC_)
PLDR_DATA_TABLE_ENTRY LdrDataTableEntry;
PVOID CurrentBase;
PLIST_ENTRY Next;
PIMAGE_NT_HEADERS NtHeader;
PIMAGE_SECTION_HEADER SectionTableEntry;
LONG i;
PMMPTE PointerPte;
PMMPTE LastPte;
BOOLEAN PageSection;
//
// Don't page kernel mode code if customer does not want it paged.
//
if (MmDisablePagingExecutive) {
return;
}
//
// Walk through the loader blocks looking for the base which
// contains this routine.
//
KeEnterCriticalRegion();
ExAcquireResourceExclusive (&PsLoadedModuleResource, TRUE);
Next = PsLoadedModuleList.Flink;
while ( Next != &PsLoadedModuleList ) {
LdrDataTableEntry = CONTAINING_RECORD( Next,
LDR_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;
NtHeader = RtlImageNtHeader(CurrentBase);
SectionTableEntry = (PIMAGE_SECTION_HEADER)((ULONG)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) {
if (MI_IS_PHYSICAL_ADDRESS (CurrentBase)) {
//
// Mapped physically, can't be paged.
//
break;
}
PageSection = (*(PULONG)SectionTableEntry->Name == 'EGAP') ||
(*(PULONG)SectionTableEntry->Name == 'ade.');
if (*(PULONG)SectionTableEntry->Name == 'EGAP' &&
SectionTableEntry->Name[4] == 'K' &&
SectionTableEntry->Name[5] == 'D') {
//
// Only pageout PAGEKD if KdPitchDebugger is TRUE
//
PageSection = KdPitchDebugger;
}
if (PageSection) {
//
// This section is pagable, save away the start and end.
//
if (PointerPte == NULL) {
//
// Previous section was NOT pagable, get the start address.
//
PointerPte = MiGetPteAddress (ROUND_TO_PAGES (
(ULONG)CurrentBase +
SectionTableEntry->VirtualAddress));
}
LastPte = MiGetPteAddress ((ULONG)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) {
MiEnablePagingOfDriverAtInit (PointerPte, LastPte);
PointerPte = NULL;
}
}
i -= 1;
SectionTableEntry += 1;
} //end while
if (PointerPte != NULL) {
MiEnablePagingOfDriverAtInit (PointerPte, LastPte);
}
Next = Next->Flink;
} //end while
ExReleaseResource (&PsLoadedModuleResource);
KeLeaveCriticalRegion();
#endif
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.
--*/
{
PVOID Base;
ULONG PageFrameIndex;
PMMPFN Pfn;
MMPTE TempPte;
KIRQL OldIrql;
LOCK_PFN (OldIrql);
Base = MiGetVirtualAddressMappedByPte (PointerPte);
while (PointerPte <= LastPte) {
ASSERT (PointerPte->u.Hard.Valid == 1);
PageFrameIndex = PointerPte->u.Hard.PageFrameNumber;
Pfn = MI_PFN_ELEMENT (PageFrameIndex);
ASSERT (Pfn->u2.ShareCount == 1);
//
// Set the working set index to zero. This allows page table
// pages to be brough back in with the proper WSINDEX.
//
Pfn->u1.WsIndex = 0;
Pfn->OriginalPte.u.Long = MM_KERNEL_DEMAND_ZERO_PTE;
Pfn->u3.e1.Modified = 1;
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 transiton.
//
MiDecrementShareCount (PageFrameIndex);
Base = (PVOID)((PCHAR)Base + PAGE_SIZE);
PointerPte += 1;
MmResidentAvailablePages += 1;
MiChargeCommitmentCantExpand (1, TRUE);
MmTotalSystemCodePages += 1;
}
UNLOCK_PFN (OldIrql);
return;
}
MM_SYSTEMSIZE
MmQuerySystemSize(
VOID
)
{
//
// 12Mb is small
// 12-19 is medium
// > 19 is large
//
return MmSystemSize;
}
NTKERNELAPI
BOOLEAN
MmIsThisAnNtAsSystem(
VOID
)
{
return (BOOLEAN)MmProductType;
}