Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

mminit.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 mminit.c 00008 00009 Abstract: 00010 00011 This module contains the initialization for the memory management 00012 system. 00013 00014 Author: 00015 00016 Lou Perazzoli (loup) 20-Mar-1989 00017 Landy Wang (landyw) 02-Jun-1997 00018 00019 Revision History: 00020 00021 --*/ 00022 00023 #include "mi.h" 00024 00025 MMPTE MmSharedUserDataPte; 00026 00027 extern MMINPAGE_SUPPORT_LIST MmInPageSupportList; 00028 extern MMEVENT_COUNT_LIST MmEventCountList; 00029 extern KMUTANT MmSystemLoadLock; 00030 extern ULONG_PTR MmSystemPtesStart[MaximumPtePoolTypes]; 00031 extern ULONG MiSpecialPoolPtes; 00032 extern ULONG MmPagedPoolCommit; 00033 00034 extern PVOID BBTBuffer; 00035 extern ULONG BBTPagesToReserve; 00036 00037 ULONG_PTR MmSubsectionBase; 00038 ULONG_PTR MmSubsectionTopPage; 00039 ULONG MmDataClusterSize; 00040 ULONG MmCodeClusterSize; 00041 PFN_NUMBER MmResidentAvailableAtInit; 00042 KEVENT MmImageMappingPteEvent; 00043 PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock; 00044 LIST_ENTRY MmLockConflictList; 00045 LOGICAL MmPagedPoolMaximumDesired = FALSE; 00046 00047 PERFINFO_MMINIT_DECL; 00048 00049 VOID 00050 MiMapBBTMemory ( 00051 IN PLOADER_PARAMETER_BLOCK LoaderBlock 00052 ); 00053 00054 VOID 00055 MiInitializeSpecialPool( 00056 VOID 00057 ); 00058 00059 VOID 00060 MiEnablePagingTheExecutive( 00061 VOID 00062 ); 00063 00064 VOID 00065 MiEnablePagingOfDriverAtInit ( 00066 IN PMMPTE PointerPte, 00067 IN PMMPTE LastPte 00068 ); 00069 00070 VOID 00071 MiBuildPagedPool ( 00072 ); 00073 00074 VOID 00075 MiMergeMemoryLimit ( 00076 IN OUT PPHYSICAL_MEMORY_DESCRIPTOR Memory, 00077 IN PFN_NUMBER StartPage, 00078 IN PFN_NUMBER NumberOfPages 00079 ); 00080 00081 VOID 00082 MiWriteProtectSystemImage ( 00083 IN PVOID DllBase 00084 ); 00085 00086 #ifndef NO_POOL_CHECKS 00087 VOID 00088 MiInitializeSpecialPoolCriteria ( 00089 IN VOID 00090 ); 00091 #endif 00092 00093 #if defined (_X86PAE_) 00094 VOID 00095 MiCheckPaeLicense ( 00096 IN PLOADER_PARAMETER_BLOCK LoaderBlock, 00097 IN PBOOLEAN IncludeType, 00098 OUT PPHYSICAL_MEMORY_DESCRIPTOR Memory 00099 ); 00100 #endif 00101 00102 #ifdef ALLOC_PRAGMA 00103 #pragma alloc_text(INIT,MmInitSystem) 00104 #pragma alloc_text(INIT,MiMapBBTMemory) 00105 #pragma alloc_text(INIT,MmInitializeMemoryLimits) 00106 #pragma alloc_text(INIT,MiMergeMemoryLimit) 00107 #pragma alloc_text(INIT,MmFreeLoaderBlock) 00108 #pragma alloc_text(INIT,MiBuildPagedPool) 00109 #pragma alloc_text(INIT,MiFindInitializationCode) 00110 #pragma alloc_text(INIT,MiEnablePagingTheExecutive) 00111 #pragma alloc_text(INIT,MiEnablePagingOfDriverAtInit) 00112 #if defined (_X86PAE_) 00113 #pragma alloc_text(INIT,MiCheckPaeLicense) 00114 #endif 00115 #pragma alloc_text(PAGELK,MiFreeInitializationCode) 00116 #endif 00117 00118 #define MM_MAX_LOADER_BLOCKS 30 00119 00120 // 00121 // Default is a 300 second life span for modified mapped pages - 00122 // This can be overridden in the registry. 00123 // 00124 00125 ULONG MmModifiedPageLifeInSeconds = 300; 00126 00127 LARGE_INTEGER MiModifiedPageLife; 00128 00129 BOOLEAN MiTimerPending = FALSE; 00130 00131 KEVENT MiMappedPagesTooOldEvent; 00132 00133 KDPC MiModifiedPageWriterTimerDpc; 00134 00135 KTIMER MiModifiedPageWriterTimer; 00136 00137 // 00138 // The following constants are based on the number PAGES not the 00139 // memory size. For convenience the number of pages is calculated 00140 // based on a 4k page size. Hence 12mb with 4k page is 3072. 00141 // 00142 00143 #define MM_SMALL_SYSTEM ((13*1024*1024) / 4096) 00144 00145 #define MM_MEDIUM_SYSTEM ((19*1024*1024) / 4096) 00146 00147 #define MM_MIN_INITIAL_PAGED_POOL ((32*1024*1024) >> PAGE_SHIFT) 00148 00149 #define MM_DEFAULT_IO_LOCK_LIMIT (2 * 1024 * 1024) 00150 00151 extern ULONG MmMaximumWorkingSetSize; 00152 00153 extern ULONG MmEnforceWriteProtection; 00154 00155 extern CHAR MiPteStr[]; 00156 00157 extern LONG MiTrimInProgressCount; 00158 00159 #if !defined (_WIN64) 00160 00161 #if !defined (_X86PAE_) 00162 PFN_NUMBER MmSystemPageDirectory; 00163 #else 00164 PFN_NUMBER MmSystemPageDirectory[PD_PER_SYSTEM]; 00165 #endif 00166 00167 PMMPTE MmSystemPagePtes; 00168 #endif 00169 00170 ULONG MmTotalSystemCodePages; 00171 00172 MM_SYSTEMSIZE MmSystemSize; 00173 00174 ULONG MmLargeSystemCache; 00175 00176 ULONG MmProductType; 00177 00178 LIST_ENTRY MmLoadedUserImageList; 00179 PPAGE_FAULT_NOTIFY_ROUTINE MmPageFaultNotifyRoutine; 00180 PHARD_FAULT_NOTIFY_ROUTINE MmHardFaultNotifyRoutine; 00181 00182 00183 BOOLEAN 00184 MmInitSystem ( 00185 IN ULONG Phase, 00186 IN PLOADER_PARAMETER_BLOCK LoaderBlock, 00187 IN PPHYSICAL_MEMORY_DESCRIPTOR PhysicalMemoryBlock 00188 ) 00189 00190 /*++ 00191 00192 Routine Description: 00193 00194 This function is called during Phase 0, phase 1 and at the end 00195 of phase 1 ("phase 2") initialization. 00196 00197 Phase 0 initializes the memory management paging functions, 00198 nonpaged and paged pool, the PFN database, etc. 00199 00200 Phase 1 initializes the section objects, the physical memory 00201 object, and starts the memory management system threads. 00202 00203 Phase 2 frees memory used by the OsLoader. 00204 00205 Arguments: 00206 00207 Phase - System initialization phase. 00208 00209 LoaderBlock - Supplies a pointer to the system loader block. 00210 00211 Return Value: 00212 00213 Returns TRUE if the initialization was successful. 00214 00215 Environment: 00216 00217 Kernel Mode Only. System initialization. 00218 00219 --*/ 00220 00221 { 00222 HANDLE ThreadHandle; 00223 OBJECT_ATTRIBUTES ObjectAttributes; 00224 PMMPTE PointerPte; 00225 PMMPTE PointerPde; 00226 PMMPTE StartPde; 00227 PMMPTE StartPpe; 00228 PMMPTE StartingPte; 00229 PMMPTE EndPde; 00230 PMMPFN Pfn1; 00231 MMPTE Pointer; 00232 PFN_NUMBER i, j; 00233 PFN_NUMBER PageFrameIndex; 00234 PFN_NUMBER DirectoryFrameIndex; 00235 MMPTE TempPte; 00236 KIRQL OldIrql; 00237 LOGICAL First; 00238 PLIST_ENTRY NextEntry; 00239 PLDR_DATA_TABLE_ENTRY DataTableEntry; 00240 ULONG MaximumSystemCacheSize; 00241 ULONG MaximumSystemCacheSizeTotal; 00242 PEPROCESS Process; 00243 PIMAGE_NT_HEADERS NtHeaders; 00244 ULONG_PTR SystemPteMultiplier; 00245 00246 BOOLEAN IncludeType[LoaderMaximum]; 00247 ULONG MemoryAlloc[(sizeof(PHYSICAL_MEMORY_DESCRIPTOR) + 00248 sizeof(PHYSICAL_MEMORY_RUN)*MAX_PHYSICAL_MEMORY_FRAGMENTS) / 00249 sizeof(ULONG)]; 00250 00251 PPHYSICAL_MEMORY_DESCRIPTOR Memory; 00252 00253 // 00254 // Make sure structure alignment is okay. 00255 // 00256 00257 if (Phase == 0) { 00258 MmThrottleTop = 450; 00259 MmThrottleBottom = 127; 00260 00261 // 00262 // Set the highest user address, the system range start address, the 00263 // user probe address, and the virtual bias. 00264 // 00265 00266 #if defined(_AXP64_) || defined(_IA64_) 00267 00268 MmHighestUserAddress = MM_HIGHEST_USER_ADDRESS; 00269 MmUserProbeAddress = MM_USER_PROBE_ADDRESS; 00270 MmSystemRangeStart = MM_SYSTEM_RANGE_START; 00271 00272 #else 00273 00274 MmHighestUserAddress = (PVOID)(KSEG0_BASE - 0x10000 - 1); 00275 MmUserProbeAddress = KSEG0_BASE - 0x10000; 00276 MmSystemRangeStart = (PVOID)KSEG0_BASE; 00277 00278 #endif 00279 00280 MiHighestUserPte = MiGetPteAddress (MmHighestUserAddress); 00281 MiHighestUserPde = MiGetPdeAddress (MmHighestUserAddress); 00282 00283 MmVirtualBias = 0; 00284 00285 // 00286 // Set the highest section base address. 00287 // 00288 // N.B. In 32-bit systems this address must be 2gb or less even for 00289 // systems that run with 3gb enabled. Otherwise, it would not 00290 // be possible to map based sections identically in all processes. 00291 // 00292 00293 MmHighSectionBase = ((PCHAR)MmHighestUserAddress - 0x800000); 00294 00295 if (ExVerifySuite(TerminalServer) == TRUE) { 00296 MiHydra = TRUE; 00297 MiSystemViewStart = MM_SYSTEM_VIEW_START_IF_HYDRA; 00298 MmSessionBase = (ULONG_PTR)MM_SESSION_SPACE_DEFAULT; 00299 00300 } else { 00301 MiSystemViewStart = MM_SYSTEM_VIEW_START; 00302 MiHydra = FALSE; 00303 } 00304 00305 MaximumSystemCacheSize = (MM_SYSTEM_CACHE_END - MM_SYSTEM_CACHE_START) >> PAGE_SHIFT; 00306 00307 // 00308 // If the system has been biased to an alternate base address to 00309 // allow 3gb of user address space, then set the user probe address 00310 // and the maximum system cache size. 00311 // 00312 00313 #if defined(_X86_) 00314 00315 MmVirtualBias = LoaderBlock->u.I386.VirtualBias; 00316 00317 if (MmVirtualBias != 0) { 00318 MmHighestUserAddress = ((PCHAR)MmHighestUserAddress + 0x40000000); 00319 MmSystemRangeStart = ((PCHAR)MmSystemRangeStart + 0x40000000); 00320 MmUserProbeAddress += 0x40000000; 00321 MiMaximumWorkingSet += 0x40000000 >> PAGE_SHIFT; 00322 00323 MiHighestUserPte = MiGetPteAddress (MmHighestUserAddress); 00324 MiHighestUserPde = MiGetPdeAddress (MmHighestUserAddress); 00325 00326 MaximumSystemCacheSize -= MM_BOOT_IMAGE_SIZE >> PAGE_SHIFT; 00327 00328 if (MiHydra == TRUE) { 00329 00330 // 00331 // Moving to 3GB means moving session space to just above 00332 // the system cache (and lowering the system cache max size 00333 // accordingly). 00334 // 00335 00336 MaximumSystemCacheSize -= (MI_SESSION_SPACE_TOTAL_SIZE + MM_SYSTEM_VIEW_SIZE_IF_HYDRA) >> PAGE_SHIFT; 00337 00338 MiSystemViewStart = (ULONG_PTR)(MM_SYSTEM_CACHE_START + 00339 (MaximumSystemCacheSize << PAGE_SHIFT)); 00340 00341 MmSessionBase = MiSystemViewStart + MM_SYSTEM_VIEW_SIZE_IF_HYDRA + MM_BOOT_IMAGE_SIZE; 00342 00343 } else { 00344 MaximumSystemCacheSize -= MM_SYSTEM_VIEW_SIZE >> PAGE_SHIFT; 00345 MiSystemViewStart = (ULONG_PTR)(MM_SYSTEM_CACHE_START + 00346 (MaximumSystemCacheSize << PAGE_SHIFT) + 00347 MM_BOOT_IMAGE_SIZE); 00348 } 00349 } 00350 00351 #else 00352 00353 if (MiHydra == TRUE) { 00354 MaximumSystemCacheSize -= MM_SYSTEM_VIEW_SIZE_IF_HYDRA >> PAGE_SHIFT; 00355 MiSystemViewStart = MM_SYSTEM_VIEW_START_IF_HYDRA; 00356 } 00357 00358 #endif 00359 00360 if (MiHydra == TRUE) { 00361 MmSessionSpace = (PMM_SESSION_SPACE)((ULONG_PTR)MmSessionBase + MI_SESSION_IMAGE_SIZE); 00362 00363 MiSessionBasePte = MiGetPteAddress (MmSessionBase); 00364 MiSessionLastPte = MiGetPteAddress (MI_SESSION_SPACE_END); 00365 } 00366 00367 // 00368 // A few sanity checks to ensure things are as they should be. 00369 // 00370 00371 #if DBG 00372 if ((sizeof(MMWSL) % 8) != 0) { 00373 DbgPrint("working set list is not a quadword sized structure\n"); 00374 } 00375 00376 if ((sizeof(CONTROL_AREA) % 8) != 0) { 00377 DbgPrint("control area list is not a quadword sized structure\n"); 00378 } 00379 00380 if ((sizeof(SUBSECTION) % 8) != 0) { 00381 DbgPrint("subsection list is not a quadword sized structure\n"); 00382 } 00383 00384 // 00385 // Some checks to make sure prototype PTEs can be placed in 00386 // either paged or nonpaged (prototype PTEs for paged pool are here) 00387 // can be put into pte format. 00388 // 00389 00390 PointerPte = (PMMPTE)MmPagedPoolStart; 00391 Pointer.u.Long = MiProtoAddressForPte (PointerPte); 00392 TempPte = Pointer; 00393 PointerPde = MiPteToProto(&TempPte); 00394 if (PointerPte != PointerPde) { 00395 DbgPrint("unable to map start of paged pool as prototype pte %p %p\n", 00396 PointerPde, 00397 PointerPte); 00398 } 00399 00400 PointerPte = 00401 (PMMPTE)((ULONG_PTR)MM_NONPAGED_POOL_END & ~((1 << PTE_SHIFT) - 1)); 00402 00403 Pointer.u.Long = MiProtoAddressForPte (PointerPte); 00404 TempPte = Pointer; 00405 PointerPde = MiPteToProto(&TempPte); 00406 if (PointerPte != PointerPde) { 00407 DbgPrint("unable to map end of nonpaged pool as prototype pte %p %p\n", 00408 PointerPde, 00409 PointerPte); 00410 } 00411 00412 PointerPte = (PMMPTE)(((ULONG_PTR)NON_PAGED_SYSTEM_END - 00413 0x37000 + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)); 00414 00415 for (j = 0; j < 20; j++) { 00416 Pointer.u.Long = MiProtoAddressForPte (PointerPte); 00417 TempPte = Pointer; 00418 PointerPde = MiPteToProto(&TempPte); 00419 if (PointerPte != PointerPde) { 00420 DbgPrint("unable to map end of nonpaged pool as prototype pte %p %p\n", 00421 PointerPde, 00422 PointerPte); 00423 } 00424 00425 PointerPte++; 00426 } 00427 00428 PointerPte = (PMMPTE)(((ULONG_PTR)MM_NONPAGED_POOL_END - 0x133448) & ~(ULONG_PTR)7); 00429 Pointer.u.Long = MiGetSubsectionAddressForPte (PointerPte); 00430 TempPte = Pointer; 00431 PointerPde = (PMMPTE)MiGetSubsectionAddress(&TempPte); 00432 if (PointerPte != PointerPde) { 00433 DbgPrint("unable to map end of nonpaged pool as section pte %p %p\n", 00434 PointerPde, 00435 PointerPte); 00436 00437 MiFormatPte(&TempPte); 00438 } 00439 00440 // 00441 // End of sanity checks. 00442 // 00443 00444 #endif //dbg 00445 00446 if (MmEnforceWriteProtection) { 00447 MiPteStr[0] = (CHAR)1; 00448 } 00449 00450 InitializeListHead( &MmLoadedUserImageList ); 00451 InitializeListHead( &MmLockConflictList ); 00452 00453 MmCriticalSectionTimeout.QuadPart = Int32x32To64( 00454 MmCritsectTimeoutSeconds, 00455 -10000000); 00456 00457 00458 // 00459 // Initialize PFN database mutex and System Address Space creation 00460 // mutex. 00461 // 00462 00463 ExInitializeFastMutex (&MmSectionCommitMutex); 00464 ExInitializeFastMutex (&MmSectionBasedMutex); 00465 ExInitializeFastMutex (&MmDynamicMemoryMutex); 00466 00467 KeInitializeMutant (&MmSystemLoadLock, FALSE); 00468 00469 KeInitializeEvent (&MmAvailablePagesEvent, NotificationEvent, TRUE); 00470 KeInitializeEvent (&MmAvailablePagesEventHigh, NotificationEvent, TRUE); 00471 KeInitializeEvent (&MmMappedFileIoComplete, NotificationEvent, FALSE); 00472 KeInitializeEvent (&MmImageMappingPteEvent, NotificationEvent, FALSE); 00473 KeInitializeEvent (&MmZeroingPageEvent, SynchronizationEvent, FALSE); 00474 KeInitializeEvent (&MmCollidedFlushEvent, NotificationEvent, FALSE); 00475 KeInitializeEvent (&MmCollidedLockEvent, NotificationEvent, FALSE); 00476 KeInitializeEvent (&MiMappedPagesTooOldEvent, NotificationEvent, FALSE); 00477 00478 KeInitializeDpc( &MiModifiedPageWriterTimerDpc, MiModifiedPageWriterTimerDispatch, NULL ); 00479 KeInitializeTimerEx( &MiModifiedPageWriterTimer, SynchronizationTimer ); 00480 00481 MiModifiedPageLife.QuadPart = Int32x32To64( 00482 MmModifiedPageLifeInSeconds, 00483 -10000000); 00484 00485 InitializeListHead (&MmWorkingSetExpansionHead.ListHead); 00486 InitializeListHead (&MmInPageSupportList.ListHead); 00487 InitializeListHead (&MmEventCountList.ListHead); 00488 00489 MmZeroingPageThreadActive = FALSE; 00490 00491 // 00492 // Compute physical memory blocks yet again 00493 // 00494 00495 Memory = (PPHYSICAL_MEMORY_DESCRIPTOR)&MemoryAlloc; 00496 Memory->NumberOfRuns = MAX_PHYSICAL_MEMORY_FRAGMENTS; 00497 00498 // include all memory types ... 00499 for (i=0; i < LoaderMaximum; i++) { 00500 IncludeType[i] = TRUE; 00501 } 00502 00503 // ... expect these.. 00504 IncludeType[LoaderBad] = FALSE; 00505 IncludeType[LoaderFirmwarePermanent] = FALSE; 00506 IncludeType[LoaderSpecialMemory] = FALSE; 00507 IncludeType[LoaderBBTMemory] = FALSE; 00508 00509 MmInitializeMemoryLimits(LoaderBlock, IncludeType, Memory); 00510 00511 #if defined (_X86PAE_) 00512 MiCheckPaeLicense (LoaderBlock, IncludeType, Memory); 00513 #endif 00514 00515 #if defined (_X86PAE_) || defined (_WIN64) 00516 Mm64BitPhysicalAddress = TRUE; 00517 #endif 00518 00519 // 00520 // Add all memory runs in PhysicalMemoryBlock to Memory 00521 // 00522 00523 for (i = 0; i < PhysicalMemoryBlock->NumberOfRuns; i += 1) { 00524 MiMergeMemoryLimit (Memory, 00525 PhysicalMemoryBlock->Run[i].BasePage, 00526 PhysicalMemoryBlock->Run[i].PageCount 00527 ); 00528 } 00529 00530 // 00531 // Sort and merge adjacent runs. 00532 // 00533 00534 for (i=0; i < Memory->NumberOfRuns; i++) { 00535 for (j=i+1; j < Memory->NumberOfRuns; j++) { 00536 if (Memory->Run[j].BasePage < Memory->Run[i].BasePage) { 00537 // swap runs 00538 PhysicalMemoryBlock->Run[0] = Memory->Run[j]; 00539 Memory->Run[j] = Memory->Run[i]; 00540 Memory->Run[i] = PhysicalMemoryBlock->Run[0]; 00541 } 00542 00543 if (Memory->Run[i].BasePage + Memory->Run[i].PageCount == 00544 Memory->Run[j].BasePage) { 00545 // merge runs 00546 Memory->NumberOfRuns -= 1; 00547 Memory->Run[i].PageCount += Memory->Run[j].PageCount; 00548 Memory->Run[j] = Memory->Run[Memory->NumberOfRuns]; 00549 i -= 1; 00550 break; 00551 } 00552 } 00553 } 00554 00555 // 00556 // When safebooting, don't enable special pool, the verifier or any 00557 // other options that track corruption regardless of registry settings. 00558 // 00559 00560 if (strstr(LoaderBlock->LoadOptions, SAFEBOOT_LOAD_OPTION_A)) { 00561 MmVerifyDriverBufferLength = (ULONG)-1; 00562 MmDontVerifyRandomDrivers = TRUE; 00563 MmSpecialPoolTag = (ULONG)-1; 00564 MmSnapUnloads = FALSE; 00565 MmProtectFreedNonPagedPool = FALSE; 00566 MmEnforceWriteProtection = 0; 00567 MmTrackLockedPages = FALSE; 00568 MmTrackPtes = FALSE; 00569 } 00570 else { 00571 MiTriageSystem (LoaderBlock); 00572 } 00573 00574 SystemPteMultiplier = 0; 00575 00576 if (MmNumberOfSystemPtes == 0) { 00577 #if defined (_WIN64) 00578 00579 // 00580 // 64-bit NT is not contrained by virtual address space. No 00581 // tradeoffs between nonpaged pool, paged pool and system PTEs 00582 // need to be made. So just allocate PTEs on a linear scale as 00583 // a function of the amount of RAM. 00584 // 00585 // For example on Alpha64, 4gb of RAM gets 128gb of PTEs by default. 00586 // The page table cost is the inversion of the multiplier based 00587 // on the PTE_PER_PAGE. 00588 // 00589 00590 if ((MiHydra == TRUE) && (ExpMultiUserTS == TRUE)) { 00591 SystemPteMultiplier = 128; 00592 } 00593 else { 00594 SystemPteMultiplier = 64; 00595 } 00596 if (Memory->NumberOfPages < 0x8000) { 00597 SystemPteMultiplier >>= 1; 00598 } 00599 #else 00600 if (Memory->NumberOfPages < MM_MEDIUM_SYSTEM) { 00601 MmNumberOfSystemPtes = MM_MINIMUM_SYSTEM_PTES; 00602 } else { 00603 MmNumberOfSystemPtes = MM_DEFAULT_SYSTEM_PTES; 00604 if (Memory->NumberOfPages > 8192) { 00605 MmNumberOfSystemPtes += MmNumberOfSystemPtes; 00606 00607 // 00608 // Any reasonable Hydra machine gets the maximum. 00609 // 00610 00611 if ((MiHydra == TRUE) && (ExpMultiUserTS == TRUE)) { 00612 MmNumberOfSystemPtes = MM_MAXIMUM_SYSTEM_PTES; 00613 } 00614 } 00615 } 00616 #endif 00617 } 00618 else if (MmNumberOfSystemPtes == (ULONG)-1) { 00619 00620 // 00621 // This registry setting indicates the maximum number of 00622 // system PTEs possible for this machine must be allocated. 00623 // Snap this for later reference. 00624 // 00625 00626 MiRequestedSystemPtes = MmNumberOfSystemPtes; 00627 00628 #if defined (_WIN64) 00629 SystemPteMultiplier = 256; 00630 #else 00631 MmNumberOfSystemPtes = MM_MAXIMUM_SYSTEM_PTES; 00632 #endif 00633 } 00634 00635 if (SystemPteMultiplier != 0) { 00636 if (Memory->NumberOfPages * SystemPteMultiplier > MM_MAXIMUM_SYSTEM_PTES) { 00637 MmNumberOfSystemPtes = MM_MAXIMUM_SYSTEM_PTES; 00638 } 00639 else { 00640 MmNumberOfSystemPtes = (ULONG)(Memory->NumberOfPages * SystemPteMultiplier); 00641 } 00642 } 00643 00644 if (MmNumberOfSystemPtes > MM_MAXIMUM_SYSTEM_PTES) { 00645 MmNumberOfSystemPtes = MM_MAXIMUM_SYSTEM_PTES; 00646 } 00647 00648 if (MmNumberOfSystemPtes < MM_MINIMUM_SYSTEM_PTES) { 00649 MmNumberOfSystemPtes = MM_MINIMUM_SYSTEM_PTES; 00650 } 00651 00652 if (MmHeapSegmentReserve == 0) { 00653 MmHeapSegmentReserve = 1024 * 1024; 00654 } 00655 00656 if (MmHeapSegmentCommit == 0) { 00657 MmHeapSegmentCommit = PAGE_SIZE * 2; 00658 } 00659 00660 if (MmHeapDeCommitTotalFreeThreshold == 0) { 00661 MmHeapDeCommitTotalFreeThreshold = 64 * 1024; 00662 } 00663 00664 if (MmHeapDeCommitFreeBlockThreshold == 0) { 00665 MmHeapDeCommitFreeBlockThreshold = PAGE_SIZE; 00666 } 00667 00668 #ifndef NO_POOL_CHECKS 00669 MiInitializeSpecialPoolCriteria (); 00670 #endif 00671 00672 // 00673 // If the registry indicates drivers are in the suspect list, 00674 // extra system PTEs need to be allocated to support special pool 00675 // for their allocations. 00676 // 00677 00678 if ((MmVerifyDriverBufferLength != (ULONG)-1) || 00679 ((MmSpecialPoolTag != 0) && (MmSpecialPoolTag != (ULONG)-1))) { 00680 MmNumberOfSystemPtes += MM_SPECIAL_POOL_PTES; 00681 } 00682 00683 MmNumberOfSystemPtes += BBTPagesToReserve; 00684 00685 // 00686 // Initialize the machine dependent portion of the hardware. 00687 // 00688 00689 ExInitializeResource (&MmSystemWsLock); 00690 00691 MiInitMachineDependent (LoaderBlock); 00692 00693 #if PFN_CONSISTENCY 00694 MiPfnProtectionEnabled = TRUE; 00695 #endif 00696 00697 MiReloadBootLoadedDrivers (LoaderBlock); 00698 00699 MiInitializeDriverVerifierList (LoaderBlock); 00700 00701 j = (sizeof(PHYSICAL_MEMORY_DESCRIPTOR) + 00702 (sizeof(PHYSICAL_MEMORY_RUN) * 00703 (Memory->NumberOfRuns - 1))); 00704 00705 MmPhysicalMemoryBlock = ExAllocatePoolWithTag (NonPagedPoolMustSucceed, 00706 j, 00707 ' mM'); 00708 00709 RtlCopyMemory (MmPhysicalMemoryBlock, Memory, j); 00710 00711 // 00712 // Setup the system size as small, medium, or large depending 00713 // on memory available. 00714 // 00715 // For internal MM tuning, the following applies 00716 // 00717 // 12Mb is small 00718 // 12-19 is medium 00719 // > 19 is large 00720 // 00721 // 00722 // For all other external tuning, 00723 // < 19 is small 00724 // 19 - 31 is medium for workstation 00725 // 19 - 63 is medium for server 00726 // >= 32 is large for workstation 00727 // >= 64 is large for server 00728 // 00729 00730 MmReadClusterSize = 7; 00731 if (MmNumberOfPhysicalPages <= MM_SMALL_SYSTEM ) { 00732 MmSystemSize = MmSmallSystem; 00733 MmMaximumDeadKernelStacks = 0; 00734 MmModifiedPageMinimum = 40; 00735 MmModifiedPageMaximum = 100; 00736 MmDataClusterSize = 0; 00737 MmCodeClusterSize = 1; 00738 MmReadClusterSize = 2; 00739 00740 } else if (MmNumberOfPhysicalPages <= MM_MEDIUM_SYSTEM ) { 00741 MmSystemSize = MmSmallSystem; 00742 MmMaximumDeadKernelStacks = 2; 00743 MmModifiedPageMinimum = 80; 00744 MmModifiedPageMaximum = 150; 00745 MmSystemCacheWsMinimum += 100; 00746 MmSystemCacheWsMaximum += 150; 00747 MmDataClusterSize = 1; 00748 MmCodeClusterSize = 2; 00749 MmReadClusterSize = 4; 00750 00751 } else { 00752 MmSystemSize = MmMediumSystem; 00753 MmMaximumDeadKernelStacks = 5; 00754 MmModifiedPageMinimum = 150; 00755 MmModifiedPageMaximum = 300; 00756 MmSystemCacheWsMinimum += 400; 00757 MmSystemCacheWsMaximum += 800; 00758 MmDataClusterSize = 3; 00759 MmCodeClusterSize = 7; 00760 } 00761 00762 if (MmNumberOfPhysicalPages < ((24*1024*1024)/PAGE_SIZE)) { 00763 MmSystemCacheWsMinimum = 32; 00764 } 00765 00766 if (MmNumberOfPhysicalPages >= ((32*1024*1024)/PAGE_SIZE)) { 00767 00768 // 00769 // If we are on a workstation, 32Mb and above are considered large systems 00770 // 00771 if ( MmProductType == 0x00690057 ) { 00772 MmSystemSize = MmLargeSystem; 00773 00774 } else { 00775 00776 // 00777 // For servers, 64Mb and greater is a large system 00778 // 00779 00780 if (MmNumberOfPhysicalPages >= ((64*1024*1024)/PAGE_SIZE)) { 00781 MmSystemSize = MmLargeSystem; 00782 } 00783 } 00784 } 00785 00786 if (MmNumberOfPhysicalPages > ((33*1024*1024)/PAGE_SIZE)) { 00787 MmModifiedPageMinimum = 400; 00788 MmModifiedPageMaximum = 800; 00789 MmSystemCacheWsMinimum += 500; 00790 MmSystemCacheWsMaximum += 900; 00791 } 00792 00793 // 00794 // determine if we are on an AS system ( Winnt is not AS) 00795 // 00796 00797 if (MmProductType == 0x00690057) { 00798 SharedUserData->NtProductType = NtProductWinNt; 00799 MmProductType = 0; 00800 MmThrottleTop = 250; 00801 MmThrottleBottom = 30; 00802 00803 } else { 00804 if ( MmProductType == 0x0061004c ) { 00805 SharedUserData->NtProductType = NtProductLanManNt; 00806 00807 } else { 00808 SharedUserData->NtProductType = NtProductServer; 00809 } 00810 00811 MmProductType = 1; 00812 MmThrottleTop = 450; 00813 MmThrottleBottom = 80; 00814 MmMinimumFreePages = 81; 00815 } 00816 00817 MiAdjustWorkingSetManagerParameters((BOOLEAN)(MmProductType == 0 ? TRUE : FALSE)); 00818 00819 // 00820 // Set the ResidentAvailablePages to the number of available 00821 // pages minus the fluid value. 00822 // 00823 00824 MmResidentAvailablePages = MmAvailablePages - MM_FLUID_PHYSICAL_PAGES; 00825 00826 // 00827 // Subtract off the size of the system cache working set. 00828 // 00829 00830 MmResidentAvailablePages -= MmSystemCacheWsMinimum; 00831 MmResidentAvailableAtInit = MmResidentAvailablePages; 00832 00833 00834 if (MmResidentAvailablePages < 0) { 00835 #if DBG 00836 DbgPrint("system cache working set too big\n"); 00837 #endif 00838 return FALSE; 00839 } 00840 00841 // 00842 // Initialize spin lock for charging and releasing page file 00843 // commitment. 00844 // 00845 00846 KeInitializeSpinLock (&MmChargeCommitmentLock); 00847 00848 MiInitializeIoTrackers (); 00849 00850 // 00851 // Initialize spin lock for allowing working set expansion. 00852 // 00853 00854 KeInitializeSpinLock (&MmExpansionLock); 00855 00856 ExInitializeFastMutex (&MmPageFileCreationLock); 00857 00858 // 00859 // Initialize resource for extending sections. 00860 // 00861 00862 ExInitializeResource (&MmSectionExtendResource); 00863 ExInitializeResource (&MmSectionExtendSetResource); 00864 00865 // 00866 // Build the system cache structures. 00867 // 00868 00869 StartPde = MiGetPdeAddress (MmSystemCacheWorkingSetList); 00870 PointerPte = MiGetPteAddress (MmSystemCacheWorkingSetList); 00871 00872 #if defined (_WIN64) 00873 00874 StartPpe = MiGetPteAddress(StartPde); 00875 00876 TempPte = ValidKernelPte; 00877 00878 if (StartPpe->u.Hard.Valid == 0) { 00879 00880 // 00881 // Map in a page directory page for the system cache working set. 00882 // Note that we only populate one page table for this. 00883 // 00884 00885 DirectoryFrameIndex = MiRemoveAnyPage( 00886 MI_GET_PAGE_COLOR_FROM_PTE (StartPpe)); 00887 TempPte.u.Hard.PageFrameNumber = DirectoryFrameIndex; 00888 *StartPpe = TempPte; 00889 00890 00891 Pfn1 = MI_PFN_ELEMENT(DirectoryFrameIndex); 00892 Pfn1->PteFrame = MI_GET_PAGE_FRAME_FROM_PTE ( 00893 MiGetPteAddress(PDE_KTBASE)); 00894 Pfn1->PteAddress = StartPpe; 00895 Pfn1->u2.ShareCount += 1; 00896 Pfn1->u3.e2.ReferenceCount = 1; 00897 Pfn1->u3.e1.PageLocation = ActiveAndValid; 00898 Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE; 00899 00900 MiFillMemoryPte (StartPde, 00901 PAGE_SIZE, 00902 ZeroKernelPte.u.Long); 00903 } 00904 00905 // 00906 // Map in a page table page. 00907 // 00908 00909 ASSERT (StartPde->u.Hard.Valid == 0); 00910 00911 PageFrameIndex = MiRemoveAnyPage( 00912 MI_GET_PAGE_COLOR_FROM_PTE (StartPde)); 00913 TempPte.u.Hard.PageFrameNumber = PageFrameIndex; 00914 MI_WRITE_VALID_PTE (StartPde, TempPte); 00915 00916 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 00917 Pfn1->PteFrame = DirectoryFrameIndex; 00918 Pfn1->PteAddress = StartPde; 00919 Pfn1->u2.ShareCount += 1; 00920 Pfn1->u3.e2.ReferenceCount = 1; 00921 Pfn1->u3.e1.PageLocation = ActiveAndValid; 00922 Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE; 00923 00924 MiFillMemoryPte (MiGetVirtualAddressMappedByPte (StartPde), 00925 PAGE_SIZE, 00926 ZeroKernelPte.u.Long); 00927 00928 StartPpe = MiGetPpeAddress(MmSystemCacheStart); 00929 StartPde = MiGetPdeAddress(MmSystemCacheStart); 00930 PointerPte = MiGetVirtualAddressMappedByPte (StartPde); 00931 00932 #else 00933 #if !defined(_X86PAE_) 00934 ASSERT ((StartPde + 1) == MiGetPdeAddress (MmSystemCacheStart)); 00935 #endif 00936 #endif 00937 00938 MaximumSystemCacheSizeTotal = MaximumSystemCacheSize; 00939 00940 #if defined(_X86_) 00941 MaximumSystemCacheSizeTotal += MiMaximumSystemCacheSizeExtra; 00942 #endif 00943 00944 // 00945 // Size the system cache based on the amount of physical memory. 00946 // 00947 00948 i = (MmNumberOfPhysicalPages + 65) / 1024; 00949 00950 if (i >= 4) { 00951 00952 // 00953 // System has at least 4032 pages. Make the system 00954 // cache 128mb + 64mb for each additional 1024 pages. 00955 // 00956 00957 MmSizeOfSystemCacheInPages = (PFN_COUNT)( 00958 ((128*1024*1024) >> PAGE_SHIFT) + 00959 ((i - 4) * ((64*1024*1024) >> PAGE_SHIFT))); 00960 if (MmSizeOfSystemCacheInPages > MaximumSystemCacheSizeTotal) { 00961 MmSizeOfSystemCacheInPages = MaximumSystemCacheSizeTotal; 00962 } 00963 } 00964 00965 MmSystemCacheEnd = (PVOID)(((PCHAR)MmSystemCacheStart + 00966 MmSizeOfSystemCacheInPages * PAGE_SIZE) - 1); 00967 00968 #if defined(_X86_) 00969 if (MmSizeOfSystemCacheInPages > MaximumSystemCacheSize) { 00970 ASSERT (MiMaximumSystemCacheSizeExtra != 0); 00971 MmSystemCacheEnd = (PVOID)(((PCHAR)MmSystemCacheStart + 00972 MaximumSystemCacheSize * PAGE_SIZE) - 1); 00973 00974 MiSystemCacheStartExtra = (PVOID)MM_SYSTEM_CACHE_START_EXTRA; 00975 MiSystemCacheEndExtra = (PVOID)(((PCHAR)MiSystemCacheStartExtra + 00976 (MmSizeOfSystemCacheInPages - MaximumSystemCacheSize) * PAGE_SIZE) - 1); 00977 } 00978 else { 00979 MiSystemCacheStartExtra = MmSystemCacheStart; 00980 MiSystemCacheEndExtra = MmSystemCacheEnd; 00981 } 00982 #endif 00983 00984 EndPde = MiGetPdeAddress(MmSystemCacheEnd); 00985 00986 TempPte = ValidKernelPte; 00987 00988 #if defined(_WIN64) 00989 First = (StartPpe->u.Hard.Valid == 0) ? TRUE : FALSE; 00990 #endif 00991 00992 #if !defined (_WIN64) 00993 DirectoryFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (MiGetPteAddress(PDE_BASE)); 00994 #endif 00995 00996 LOCK_PFN (OldIrql); 00997 while (StartPde <= EndPde) { 00998 00999 #if defined (_WIN64) 01000 if (First == TRUE || MiIsPteOnPdeBoundary(StartPde)) { 01001 First = FALSE; 01002 StartPpe = MiGetPteAddress(StartPde); 01003 01004 // 01005 // Map in a page directory page. 01006 // 01007 01008 DirectoryFrameIndex = MiRemoveAnyPage( 01009 MI_GET_PAGE_COLOR_FROM_PTE (StartPpe)); 01010 TempPte.u.Hard.PageFrameNumber = DirectoryFrameIndex; 01011 *StartPpe = TempPte; 01012 01013 Pfn1 = MI_PFN_ELEMENT(DirectoryFrameIndex); 01014 Pfn1->PteFrame = MI_GET_PAGE_FRAME_FROM_PTE ( 01015 MiGetPteAddress(PDE_KTBASE)); 01016 Pfn1->PteAddress = StartPpe; 01017 Pfn1->u2.ShareCount += 1; 01018 Pfn1->u3.e2.ReferenceCount = 1; 01019 Pfn1->u3.e1.PageLocation = ActiveAndValid; 01020 Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE; 01021 01022 MiFillMemoryPte (StartPde, 01023 PAGE_SIZE, 01024 ZeroKernelPte.u.Long); 01025 } 01026 #endif 01027 01028 ASSERT (StartPde->u.Hard.Valid == 0); 01029 01030 // 01031 // Map in a page table page. 01032 // 01033 01034 PageFrameIndex = MiRemoveAnyPage( 01035 MI_GET_PAGE_COLOR_FROM_PTE (StartPde)); 01036 TempPte.u.Hard.PageFrameNumber = PageFrameIndex; 01037 MI_WRITE_VALID_PTE (StartPde, TempPte); 01038 01039 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 01040 Pfn1->PteFrame = DirectoryFrameIndex; 01041 Pfn1->PteAddress = StartPde; 01042 Pfn1->u2.ShareCount += 1; 01043 Pfn1->u3.e2.ReferenceCount = 1; 01044 Pfn1->u3.e1.PageLocation = ActiveAndValid; 01045 Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE; 01046 01047 MiFillMemoryPte (PointerPte, 01048 PAGE_SIZE, 01049 ZeroKernelPte.u.Long); 01050 01051 StartPde += 1; 01052 PointerPte += PTE_PER_PAGE; 01053 } 01054 01055 #if defined(_X86_) 01056 if (MiSystemCacheEndExtra != MmSystemCacheEnd) { 01057 01058 StartPde = MiGetPdeAddress (MiSystemCacheStartExtra); 01059 EndPde = MiGetPdeAddress(MiSystemCacheEndExtra); 01060 01061 PointerPte = MiGetPteAddress (MiSystemCacheStartExtra); 01062 01063 while (StartPde <= EndPde) { 01064 01065 ASSERT (StartPde->u.Hard.Valid == 0); 01066 01067 // 01068 // Map in a page directory page. 01069 // 01070 01071 PageFrameIndex = MiRemoveAnyPage( 01072 MI_GET_PAGE_COLOR_FROM_PTE (StartPde)); 01073 TempPte.u.Hard.PageFrameNumber = PageFrameIndex; 01074 MI_WRITE_VALID_PTE (StartPde, TempPte); 01075 01076 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 01077 Pfn1->PteFrame = MI_GET_PAGE_FRAME_FROM_PTE ( 01078 MiGetPdeAddress(PDE_BASE)); 01079 Pfn1->PteAddress = StartPde; 01080 Pfn1->u2.ShareCount += 1; 01081 Pfn1->u3.e2.ReferenceCount = 1; 01082 Pfn1->u3.e1.PageLocation = ActiveAndValid; 01083 Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE; 01084 01085 MiFillMemoryPte (PointerPte, 01086 PAGE_SIZE, 01087 ZeroKernelPte.u.Long); 01088 01089 StartPde += 1; 01090 PointerPte += PTE_PER_PAGE; 01091 } 01092 } 01093 #endif 01094 01095 UNLOCK_PFN (OldIrql); 01096 01097 // 01098 // Initialize the system cache. Only set the large system cache if 01099 // we have a large amount of physical memory. 01100 // 01101 01102 if (MmLargeSystemCache != 0 && MmNumberOfPhysicalPages > 0x7FF0) { 01103 if ((MmAvailablePages > 01104 MmSystemCacheWsMaximum + ((64*1024*1024) >> PAGE_SHIFT))) { 01105 MmSystemCacheWsMaximum = 01106 MmAvailablePages - ((32*1024*1024) >> PAGE_SHIFT); 01107 ASSERT ((LONG)MmSystemCacheWsMaximum > (LONG)MmSystemCacheWsMinimum); 01108 MmMoreThanEnoughFreePages = 256; 01109 } 01110 } 01111 01112 if (MmSystemCacheWsMaximum > (MM_MAXIMUM_WORKING_SET - 5)) { 01113 MmSystemCacheWsMaximum = MM_MAXIMUM_WORKING_SET - 5; 01114 } 01115 01116 if (MmSystemCacheWsMaximum > MmSizeOfSystemCacheInPages) { 01117 MmSystemCacheWsMaximum = MmSizeOfSystemCacheInPages; 01118 if ((MmSystemCacheWsMinimum + 500) > MmSystemCacheWsMaximum) { 01119 MmSystemCacheWsMinimum = MmSystemCacheWsMaximum - 500; 01120 } 01121 } 01122 01123 MiInitializeSystemCache ((ULONG)MmSystemCacheWsMinimum, 01124 (ULONG)MmSystemCacheWsMaximum); 01125 01126 // 01127 // Set the commit page limit to four times the number of available 01128 // pages. This value is updated as paging files are created. 01129 // 01130 01131 MmTotalCommitLimit = MmAvailablePages << 2; 01132 MmTotalCommitLimitMaximum = MmTotalCommitLimit; 01133 01134 MmAttemptForCantExtend.Segment = NULL; 01135 MmAttemptForCantExtend.RequestedExpansionSize = 1; 01136 MmAttemptForCantExtend.ActualExpansion = 1; 01137 MmAttemptForCantExtend.InProgress = FALSE; 01138 MmAttemptForCantExtend.PageFileNumber = MI_EXTEND_ANY_PAGEFILE; 01139 01140 KeInitializeEvent (&MmAttemptForCantExtend.Event, 01141 NotificationEvent, 01142 FALSE); 01143 01144 if (MmOverCommit == 0) { 01145 01146 // If this value was not set via the registry, set the 01147 // over commit value to the number of available pages 01148 // minus 1024 pages (4mb with 4k pages). 01149 // 01150 01151 if (MmAvailablePages > 1024) { 01152 MmOverCommit = MmAvailablePages - 1024; 01153 } 01154 } 01155 01156 // 01157 // Set maximum working set size to 512 pages less total available 01158 // memory. 2mb on machine with 4k pages. 01159 // 01160 01161 MmMaximumWorkingSetSize = (ULONG)(MmAvailablePages - 512); 01162 01163 if (MmMaximumWorkingSetSize > (MM_MAXIMUM_WORKING_SET - 5)) { 01164 MmMaximumWorkingSetSize = MM_MAXIMUM_WORKING_SET - 5; 01165 } 01166 01167 // 01168 // Create the modified page writer event. 01169 // 01170 01171 KeInitializeEvent (&MmModifiedPageWriterEvent, NotificationEvent, FALSE); 01172 01173 // 01174 // Build paged pool. 01175 // 01176 01177 MiBuildPagedPool (); 01178 01179 // 01180 // Initialize the loaded module list. This cannot be done until 01181 // paged pool has been built. 01182 // 01183 01184 if (MiInitializeLoadedModuleList (LoaderBlock) == FALSE) { 01185 #if DBG 01186 DbgPrint("Loaded module list initialization failed\n"); 01187 #endif 01188 return FALSE; 01189 } 01190 01191 // 01192 // Initialize the unused segment thresholds. The assumption is made 01193 // that the filesystem will tack on approximately a 1024-byte paged 01194 // pool charge (regardless of file size) for each file in the cache. 01195 // 01196 01197 if (MmUnusedSegmentTrimLevel < 5) { 01198 MmUnusedSegmentTrimLevel = 5; 01199 } 01200 else if (MmUnusedSegmentTrimLevel > 40) { 01201 MmUnusedSegmentTrimLevel = 40; 01202 } 01203 01204 MmMaxUnusedSegmentPagedPoolUsage = (MmSizeOfPagedPoolInBytes / 100) * (MmUnusedSegmentTrimLevel << 1); 01205 MmUnusedSegmentPagedPoolReduction = MmMaxUnusedSegmentPagedPoolUsage >> 2; 01206 01207 MmMaxUnusedSegmentNonPagedPoolUsage = (MmMaximumNonPagedPoolInBytes / 100) * (MmUnusedSegmentTrimLevel << 1); 01208 MmUnusedSegmentNonPagedPoolReduction = MmMaxUnusedSegmentNonPagedPoolUsage >> 2; 01209 01210 // 01211 // Add more system PTEs if this is a large memory system. 01212 // Note that 64 bit systems can determine the right value at the 01213 // beginning since there is no virtual address space crunch. 01214 // 01215 01216 #if !defined (_WIN64) 01217 if (MmNumberOfPhysicalPages > ((127*1024*1024) >> PAGE_SHIFT)) { 01218 01219 PointerPde = MiGetPdeAddress ((PCHAR)MmPagedPoolEnd + 1); 01220 StartingPte = MiGetPteAddress ((PCHAR)MmPagedPoolEnd + 1); 01221 j = 0; 01222 01223 TempPte = ValidKernelPde; 01224 LOCK_PFN (OldIrql); 01225 while (PointerPde->u.Hard.Valid == 0) { 01226 01227 MiChargeCommitmentCantExpand (1, TRUE); 01228 MM_TRACK_COMMIT (MM_DBG_COMMIT_EXTRA_SYSTEM_PTES, 1); 01229 01230 PageFrameIndex = MiRemoveZeroPage ( 01231 MI_GET_PAGE_COLOR_FROM_PTE (PointerPde)); 01232 TempPte.u.Hard.PageFrameNumber = PageFrameIndex; 01233 MI_WRITE_VALID_PTE (PointerPde, TempPte); 01234 MiInitializePfn (PageFrameIndex, PointerPde, 1); 01235 PointerPde += 1; 01236 StartingPte += PAGE_SIZE / sizeof(MMPTE); 01237 j += PAGE_SIZE / sizeof(MMPTE); 01238 } 01239 01240 UNLOCK_PFN (OldIrql); 01241 01242 if (j != 0) { 01243 StartingPte = MiGetPteAddress ((PCHAR)MmPagedPoolEnd + 1); 01244 MmNonPagedSystemStart = MiGetVirtualAddressMappedByPte (StartingPte); 01245 MmNumberOfSystemPtes += j; 01246 MiAddSystemPtes (StartingPte, j, SystemPteSpace); 01247 } 01248 } 01249 #endif 01250 01251 01252 #if DBG 01253 if (MmDebug & MM_DBG_DUMP_BOOT_PTES) { 01254 MiDumpValidAddresses (); 01255 MiDumpPfn (); 01256 } 01257 #endif 01258 01259 MmPageFaultNotifyRoutine = NULL; 01260 MmHardFaultNotifyRoutine = NULL; 01261 01262 return TRUE; 01263 } 01264 01265 if (Phase == 1) { 01266 01267 #if DBG 01268 MmDebug |= MM_DBG_CHECK_PFN_LOCK; 01269 #endif 01270 01271 #ifdef _X86_ 01272 MiInitMachineDependent (LoaderBlock); 01273 #endif 01274 MiMapBBTMemory(LoaderBlock); 01275 01276 if (!MiSectionInitialization ()) { 01277 return FALSE; 01278 } 01279 01280 Process = PsGetCurrentProcess (); 01281 if (Process->PhysicalVadList.Flink == NULL) { 01282 KeInitializeSpinLock (&Process->AweLock); 01283 InitializeListHead (&Process->PhysicalVadList); 01284 } 01285 01286 #if defined(MM_SHARED_USER_DATA_VA) 01287 01288 // 01289 // Create double mapped page between kernel and user mode. 01290 // 01291 01292 PointerPte = MiGetPteAddress(KI_USER_SHARED_DATA); 01293 ASSERT (PointerPte->u.Hard.Valid == 1); 01294 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 01295 01296 MI_MAKE_VALID_PTE (MmSharedUserDataPte, 01297 PageFrameIndex, 01298 MM_READONLY, 01299 PointerPte); 01300 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 01301 01302 LOCK_PFN (OldIrql); 01303 01304 Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE; 01305 01306 UNLOCK_PFN (OldIrql); 01307 #endif 01308 01309 if (MiHydra == TRUE) { 01310 MiSessionWideInitializeAddresses (); 01311 MiInitializeSessionWsSupport (); 01312 MiInitializeSessionIds (); 01313 } 01314 01315 // 01316 // Set up system wide lock pages limit. 01317 // 01318 01319 if ((MmLockPagesPercentage < 5) || (MmLockPagesPercentage >= 100)) { 01320 01321 // 01322 // No (reasonable or max) registry override from the user 01323 // so default to allowing all available memory. 01324 // 01325 01326 MmLockPagesLimit = (PFN_NUMBER)-1; 01327 } 01328 else { 01329 01330 // 01331 // Use the registry value - note it is expressed as a percentage. 01332 // 01333 01334 MmLockPagesLimit = (PFN_NUMBER)((MmAvailablePages * MmLockPagesPercentage) / 100); 01335 } 01336 01337 // 01338 // Start the modified page writer. 01339 // 01340 01341 InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL ); 01342 01343 if (!NT_SUCCESS(PsCreateSystemThread( 01344 &ThreadHandle, 01345 THREAD_ALL_ACCESS, 01346 &ObjectAttributes, 01347 0L, 01348 NULL, 01349 MiModifiedPageWriter, 01350 NULL 01351 ))) { 01352 return FALSE; 01353 } 01354 ZwClose (ThreadHandle); 01355 01356 // 01357 // Start the balance set manager. 01358 // 01359 // The balance set manager performs stack swapping and working 01360 // set management and requires two threads. 01361 // 01362 01363 KeInitializeEvent (&MmWorkingSetManagerEvent, 01364 SynchronizationEvent, 01365 FALSE); 01366 01367 InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL ); 01368 01369 if (!NT_SUCCESS(PsCreateSystemThread( 01370 &ThreadHandle, 01371 THREAD_ALL_ACCESS, 01372 &ObjectAttributes, 01373 0L, 01374 NULL, 01375 KeBalanceSetManager, 01376 NULL 01377 ))) { 01378 01379 return FALSE; 01380 } 01381 ZwClose (ThreadHandle); 01382 01383 if (!NT_SUCCESS(PsCreateSystemThread( 01384 &ThreadHandle, 01385 THREAD_ALL_ACCESS, 01386 &ObjectAttributes, 01387 0L, 01388 NULL, 01389 KeSwapProcessOrStack, 01390 NULL 01391 ))) { 01392 01393 return FALSE; 01394 } 01395 ZwClose (ThreadHandle); 01396 01397 #ifndef NO_POOL_CHECKS 01398 MiInitializeSpecialPoolCriteria (); 01399 #endif 01400 01401 #if defined(_X86_) 01402 MiEnableKernelVerifier (); 01403 #endif 01404 01405 ExAcquireResourceExclusive (&PsLoadedModuleResource, TRUE); 01406 01407 NextEntry = PsLoadedModuleList.Flink; 01408 01409 for ( ; NextEntry != &PsLoadedModuleList; NextEntry = NextEntry->Flink) { 01410 01411 DataTableEntry = CONTAINING_RECORD(NextEntry, 01412 LDR_DATA_TABLE_ENTRY, 01413 InLoadOrderLinks); 01414 01415 NtHeaders = RtlImageNtHeader(DataTableEntry->DllBase); 01416 01417 if ((NtHeaders->OptionalHeader.MajorOperatingSystemVersion >= 5) && 01418 (NtHeaders->OptionalHeader.MajorImageVersion >= 5)) { 01419 DataTableEntry->Flags |= LDRP_ENTRY_NATIVE; 01420 } 01421 01422 MiWriteProtectSystemImage (DataTableEntry->DllBase); 01423 } 01424 ExReleaseResource (&PsLoadedModuleResource); 01425 01426 InterlockedDecrement (&MiTrimInProgressCount); 01427 01428 return TRUE; 01429 } 01430 01431 if (Phase == 2) { 01432 MiEnablePagingTheExecutive(); 01433 return TRUE; 01434 } 01435 01436 return FALSE; 01437 } 01438 01439 VOID 01440 MiMapBBTMemory ( 01441 IN PLOADER_PARAMETER_BLOCK LoaderBlock 01442 ) 01443 01444 /*++ 01445 01446 Routine Description: 01447 01448 This function walks through the loader block's memory descriptor list 01449 and maps memory reserved for the BBT buffer into the system. 01450 01451 The mapped PTEs are PDE-aligned and made user accessible. 01452 01453 Arguments: 01454 01455 LoaderBlock - Supplies a pointer to the system loader block. 01456 01457 Return Value: 01458 01459 None. 01460 01461 Environment: 01462 01463 Kernel Mode Only. System initialization. 01464 01465 --*/ 01466 { 01467 PVOID Va; 01468 PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor; 01469 PLIST_ENTRY NextMd; 01470 PFN_NUMBER NumberOfPagesMapped; 01471 PFN_NUMBER NumberOfPages; 01472 PFN_NUMBER PageFrameIndex; 01473 PMMPTE PointerPte; 01474 PMMPTE PointerPde; 01475 PMMPTE LastPde; 01476 MMPTE TempPte; 01477 01478 if (BBTPagesToReserve <= 0) { 01479 return; 01480 } 01481 01482 // 01483 // Request enough PTEs such that protection can be applied to the PDEs. 01484 // 01485 01486 NumberOfPages = (BBTPagesToReserve + (PTE_PER_PAGE - 1)) & ~(PTE_PER_PAGE - 1); 01487 01488 PointerPte = MiReserveSystemPtes((ULONG)NumberOfPages, 01489 SystemPteSpace, 01490 MM_VA_MAPPED_BY_PDE, 01491 0, 01492 FALSE); 01493 01494 if (PointerPte == NULL) { 01495 BBTPagesToReserve = 0; 01496 return; 01497 } 01498 01499 // 01500 // Allow user access to the buffer. 01501 // 01502 01503 PointerPde = MiGetPteAddress (PointerPte); 01504 LastPde = MiGetPteAddress (PointerPte + NumberOfPages); 01505 01506 ASSERT (LastPde != PointerPde); 01507 01508 do { 01509 TempPte = *PointerPde; 01510 TempPte.u.Long |= MM_PTE_OWNER_MASK; 01511 MI_WRITE_VALID_PTE (PointerPde, TempPte); 01512 PointerPde += 1; 01513 } while (PointerPde < LastPde); 01514 01515 KeFlushEntireTb (TRUE, TRUE); 01516 01517 Va = MiGetVirtualAddressMappedByPte (PointerPte); 01518 01519 TempPte = ValidUserPte; 01520 NumberOfPagesMapped = 0; 01521 01522 NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; 01523 01524 while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { 01525 01526 MemoryDescriptor = CONTAINING_RECORD(NextMd, 01527 MEMORY_ALLOCATION_DESCRIPTOR, 01528 ListEntry); 01529 01530 if (MemoryDescriptor->MemoryType == LoaderBBTMemory) { 01531 01532 PageFrameIndex = MemoryDescriptor->BasePage; 01533 NumberOfPages = MemoryDescriptor->PageCount; 01534 01535 if (NumberOfPagesMapped + NumberOfPages > BBTPagesToReserve) { 01536 NumberOfPages = BBTPagesToReserve - NumberOfPagesMapped; 01537 } 01538 01539 NumberOfPagesMapped += NumberOfPages; 01540 01541 do { 01542 01543 TempPte.u.Hard.PageFrameNumber = PageFrameIndex; 01544 MI_WRITE_VALID_PTE (PointerPte, TempPte); 01545 01546 PointerPte += 1; 01547 PageFrameIndex += 1; 01548 NumberOfPages -= 1; 01549 } while (NumberOfPages); 01550 01551 if (NumberOfPagesMapped == BBTPagesToReserve) { 01552 break; 01553 } 01554 } 01555 01556 NextMd = MemoryDescriptor->ListEntry.Flink; 01557 } 01558 01559 RtlZeroMemory(Va, BBTPagesToReserve << PAGE_SHIFT); 01560 01561 // 01562 // Tell BBT_Init how many pages were allocated. 01563 // 01564 01565 if (NumberOfPagesMapped < BBTPagesToReserve) { 01566 BBTPagesToReserve = (ULONG)NumberOfPagesMapped; 01567 } 01568 *(PULONG)Va = BBTPagesToReserve; 01569 01570 // 01571 // At this point instrumentation code will detect the existence of 01572 // buffer and initialize the structures. 01573 // 01574 01575 BBTBuffer = Va; 01576 01577 PERFINFO_MMINIT_START(); 01578 } 01579 01580 01581 VOID 01582 MmInitializeMemoryLimits ( 01583 IN PLOADER_PARAMETER_BLOCK LoaderBlock, 01584 IN PBOOLEAN IncludeType, 01585 OUT PPHYSICAL_MEMORY_DESCRIPTOR Memory 01586 ) 01587 01588 /*++ 01589 01590 Routine Description: 01591 01592 This function walks through the loader block's memory 01593 descriptor list and builds a list of contiguous physical 01594 memory blocks of the desired types. 01595 01596 Arguments: 01597 01598 LoaderBlock - Supplies a pointer the system loader block. 01599 01600 IncludeType - Array of BOOLEANS of size LoaderMaximum. 01601 TRUE means include this type of memory in return. 01602 01603 Memory - Returns the physical memory blocks. 01604 01605 Return Value: 01606 01607 None. 01608 01609 Environment: 01610 01611 Kernel Mode Only. System initialization. 01612 01613 --*/ 01614 { 01615 01616 PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor; 01617 PLIST_ENTRY NextMd; 01618 PFN_NUMBER i; 01619 PFN_NUMBER LowestFound; 01620 PFN_NUMBER Found; 01621 PFN_NUMBER Merged; 01622 PFN_NUMBER NextPage; 01623 PFN_NUMBER TotalPages; 01624 01625 TotalPages = 0; 01626 01627 // 01628 // Walk through the memory descriptors and build the physical memory list. 01629 // 01630 01631 LowestFound = 0; 01632 Memory->Run[0].BasePage = 0xffffffff; 01633 NextPage = 0xffffffff; 01634 Memory->Run[0].PageCount = 0; 01635 i = 0; 01636 01637 do { 01638 Merged = FALSE; 01639 Found = FALSE; 01640 NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; 01641 01642 while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { 01643 01644 MemoryDescriptor = CONTAINING_RECORD(NextMd, 01645 MEMORY_ALLOCATION_DESCRIPTOR, 01646 ListEntry); 01647 01648 if (MemoryDescriptor->MemoryType < LoaderMaximum && 01649 IncludeType [MemoryDescriptor->MemoryType] ) { 01650 01651 // 01652 // Try to merge runs. 01653 // 01654 01655 if (MemoryDescriptor->BasePage == NextPage) { 01656 ASSERT (MemoryDescriptor->PageCount != 0); 01657 Memory->Run[i - 1].PageCount += MemoryDescriptor->PageCount; 01658 NextPage += MemoryDescriptor->PageCount; 01659 TotalPages += MemoryDescriptor->PageCount; 01660 Merged = TRUE; 01661 Found = TRUE; 01662 break; 01663 } 01664 01665 if (MemoryDescriptor->BasePage >= LowestFound) { 01666 if (Memory->Run[i].BasePage > MemoryDescriptor->BasePage) { 01667 Memory->Run[i].BasePage = MemoryDescriptor->BasePage; 01668 Memory->Run[i].PageCount = MemoryDescriptor->PageCount; 01669 } 01670 Found = TRUE; 01671 } 01672 } 01673 NextMd = MemoryDescriptor->ListEntry.Flink; 01674 } 01675 01676 if (!Merged && Found) { 01677 NextPage = Memory->Run[i].BasePage + Memory->Run[i].PageCount; 01678 TotalPages += Memory->Run[i].PageCount; 01679 i += 1; 01680 } 01681 Memory->Run[i].BasePage = 0xffffffff; 01682 LowestFound = NextPage; 01683 01684 } while (Found); 01685 ASSERT (i <= Memory->NumberOfRuns); 01686 Memory->NumberOfRuns = (ULONG)i; 01687 Memory->NumberOfPages = TotalPages; 01688 01689 return; 01690 } 01691 01692 #if defined (_X86PAE_) 01693 01694 static 01695 VOID 01696 MiCheckPaeLicense ( 01697 IN PLOADER_PARAMETER_BLOCK LoaderBlock, 01698 IN PBOOLEAN IncludeType, 01699 OUT PPHYSICAL_MEMORY_DESCRIPTOR Memory 01700 ) 01701 01702 /*++ 01703 01704 Routine Description: 01705 01706 This function walks through the loader block's memory descriptor list 01707 and removes descriptors above 4gb if the license does not allow them. 01708 01709 Arguments: 01710 01711 LoaderBlock - Supplies a pointer the system loader block. 01712 01713 IncludeType - Array of BOOLEANS of size LoaderMaximum. 01714 TRUE means include this type of memory in return. 01715 01716 Memory - Returns the physical memory blocks. 01717 01718 Return Value: 01719 01720 None. 01721 01722 Environment: 01723 01724 Kernel Mode Only. System initialization. 01725 01726 --*/ 01727 { 01728 PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor; 01729 PLIST_ENTRY NextMd; 01730 PFN_NUMBER i; 01731 PFN_NUMBER LowestFound; 01732 PFN_NUMBER Found; 01733 PFN_NUMBER Merged; 01734 PFN_NUMBER NextPage; 01735 PFN_NUMBER LastPage; 01736 PFN_NUMBER MaxPage; 01737 PFN_NUMBER TotalPages; 01738 static BOOLEAN BeenHere = FALSE; 01739 01740 if (BeenHere == TRUE) { 01741 return; 01742 } 01743 01744 BeenHere = TRUE; 01745 01746 // 01747 // If properly licensed for PAE (ie: DataCenter) and booted without the 01748 // 3gb switch, then use all available physical memory. 01749 // 01750 01751 if (ExVerifySuite(DataCenter) == TRUE) { 01752 01753 // 01754 // Note MmVirtualBias has not yet been initialized at the time of the 01755 // first call to this routine, so use the LoaderBlock directly. 01756 // 01757 01758 if (LoaderBlock->u.I386.VirtualBias == 0) { 01759 01760 // 01761 // Limit the maximum physical memory to the amount we have 01762 // actually physically seen in a machine inhouse. 01763 // 01764 01765 MaxPage = 8 * 1024 * 1024; 01766 } 01767 else { 01768 01769 // 01770 // The system is booting /3gb, so don't use more than 16gb of 01771 // physical memory. This ensures enough virtual space to map 01772 // the PFN database. 01773 // 01774 01775 MaxPage = 4 * 1024 * 1024; 01776 } 01777 } 01778 else if ((MmProductType != 0x00690057) && 01779 (ExVerifySuite(Enterprise) == TRUE)) { 01780 01781 // 01782 // Advanced Server is permitted a maximum of 8gb physical memory. 01783 // The system continues to operate in 8-byte PTE mode. 01784 // 01785 01786 MaxPage = 2 * 1024 * 1024; 01787 } 01788 else { 01789 01790 // 01791 // All other configurations get a maximum of 4gb physical memory. 01792 // The system continues to operate in 8-byte PTE mode. 01793 // 01794 01795 MaxPage = 1024 * 1024; 01796 } 01797 01798 TotalPages = 0; 01799 01800 // 01801 // Walk through the memory descriptors and make sure no descriptors 01802 // reach or exceed the physical addressing limit. 01803 // 01804 01805 NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; 01806 while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { 01807 01808 MemoryDescriptor = CONTAINING_RECORD(NextMd, 01809 MEMORY_ALLOCATION_DESCRIPTOR, 01810 ListEntry); 01811 01812 if (MemoryDescriptor->BasePage >= MaxPage) { 01813 MemoryDescriptor->BasePage = 0; 01814 MemoryDescriptor->PageCount = 0; 01815 } 01816 01817 LastPage = MemoryDescriptor->BasePage + MemoryDescriptor->PageCount; 01818 01819 if (LastPage >= MaxPage || LastPage < MemoryDescriptor->BasePage) { 01820 MemoryDescriptor->PageCount = MaxPage - MemoryDescriptor->BasePage - 1; 01821 } 01822 01823 NextMd = MemoryDescriptor->ListEntry.Flink; 01824 } 01825 01826 // 01827 // Walk through the memory descriptors and truncate the physical memory 01828 // list. 01829 // 01830 01831 LowestFound = 0; 01832 Memory->Run[0].BasePage = 0xffffffff; 01833 NextPage = 0xffffffff; 01834 Memory->Run[0].PageCount = 0; 01835 i = 0; 01836 01837 do { 01838 Merged = FALSE; 01839 Found = FALSE; 01840 NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; 01841 01842 while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { 01843 01844 MemoryDescriptor = CONTAINING_RECORD(NextMd, 01845 MEMORY_ALLOCATION_DESCRIPTOR, 01846 ListEntry); 01847 01848 01849 if (MemoryDescriptor->BasePage || MemoryDescriptor->PageCount) { 01850 01851 if (MemoryDescriptor->MemoryType < LoaderMaximum && 01852 IncludeType [MemoryDescriptor->MemoryType] ) { 01853 01854 // 01855 // Try to merge runs. 01856 // 01857 01858 if (MemoryDescriptor->BasePage == NextPage) { 01859 ASSERT (MemoryDescriptor->PageCount != 0); 01860 Memory->Run[i - 1].PageCount += MemoryDescriptor->PageCount; 01861 NextPage += MemoryDescriptor->PageCount; 01862 TotalPages += MemoryDescriptor->PageCount; 01863 Merged = TRUE; 01864 Found = TRUE; 01865 break; 01866 } 01867 01868 if (MemoryDescriptor->BasePage >= LowestFound) { 01869 if (Memory->Run[i].BasePage > MemoryDescriptor->BasePage) { 01870 Memory->Run[i].BasePage = MemoryDescriptor->BasePage; 01871 Memory->Run[i].PageCount = MemoryDescriptor->PageCount; 01872 } 01873 Found = TRUE; 01874 } 01875 } 01876 } 01877 NextMd = MemoryDescriptor->ListEntry.Flink; 01878 } 01879 01880 if (!Merged && Found) { 01881 NextPage = Memory->Run[i].BasePage + Memory->Run[i].PageCount; 01882 TotalPages += Memory->Run[i].PageCount; 01883 i += 1; 01884 } 01885 Memory->Run[i].BasePage = 0xffffffff; 01886 LowestFound = NextPage; 01887 01888 } while (Found); 01889 ASSERT (i <= Memory->NumberOfRuns); 01890 Memory->NumberOfRuns = (ULONG)i; 01891 Memory->NumberOfPages = TotalPages; 01892 01893 return; 01894 } 01895 #endif 01896 01897 01898 VOID 01899 MiMergeMemoryLimit ( 01900 IN OUT PPHYSICAL_MEMORY_DESCRIPTOR Memory, 01901 IN PFN_NUMBER StartPage, 01902 IN PFN_NUMBER NumberOfPages 01903 ) 01904 /*++ 01905 01906 Routine Description: 01907 01908 This function ensures the passed range is in the passed in Memory 01909 block adding any new data as needed. 01910 01911 The passed memory block is assumed to be at least 01912 MAX_PHYSICAL_MEMORY_FRAGMENTS large 01913 01914 Arguments: 01915 01916 Memory - Supplies the memory block to verify run is present in. 01917 01918 StartPage - Supplies the first page of the run. 01919 01920 NumberOfPages - Supplies the number of pages in the run. 01921 01922 Return Value: 01923 01924 None. 01925 01926 Environment: 01927 01928 Kernel Mode Only. System initialization. 01929 01930 --*/ 01931 { 01932 PFN_NUMBER EndPage, sp, ep, i; 01933 01934 EndPage = StartPage + NumberOfPages; 01935 01936 // 01937 // Clip range to area which is not already described 01938 // 01939 01940 for (i=0; i < Memory->NumberOfRuns; i++) { 01941 sp = Memory->Run[i].BasePage; 01942 ep = sp + Memory->Run[i].PageCount; 01943 01944 if (sp < StartPage) { 01945 if (ep > StartPage && ep < EndPage) { 01946 // bump beginning page of the target area 01947 StartPage = ep; 01948 } 01949 01950 if (ep > EndPage) { 01951 // 01952 // Target area is contained totally within this 01953 // descriptor. This range is fully accounted for. 01954 // 01955 01956 StartPage = EndPage; 01957 } 01958 01959 } else { 01960 // sp >= StartPage 01961 01962 if (sp < EndPage) { 01963 if (ep < EndPage) { 01964 // 01965 // This descriptor is totally within the target area - 01966 // check the area on either side of this descriptor 01967 // 01968 01969 MiMergeMemoryLimit (Memory, StartPage, sp - StartPage); 01970 StartPage = ep; 01971 01972 } else { 01973 // clip the ending page of the target area 01974 EndPage = sp; 01975 } 01976 } 01977 } 01978 01979 // 01980 // Anything left of target area? 01981 // 01982 01983 if (StartPage == EndPage) { 01984 return ; 01985 } 01986 } // next descriptor 01987 01988 // 01989 // The range StartPage - EndPage is a missing. Add it. 01990 // 01991 01992 if (Memory->NumberOfRuns == MAX_PHYSICAL_MEMORY_FRAGMENTS) { 01993 return ; 01994 } 01995 01996 Memory->Run[Memory->NumberOfRuns].BasePage = StartPage; 01997 Memory->Run[Memory->NumberOfRuns].PageCount = EndPage - StartPage; 01998 Memory->NumberOfPages += EndPage - StartPage; 01999 Memory->NumberOfRuns += 1; 02000 } 02001 02002 02003 02004 VOID 02005 MmFreeLoaderBlock ( 02006 IN PLOADER_PARAMETER_BLOCK LoaderBlock 02007 ) 02008 02009 /*++ 02010 02011 Routine Description: 02012 02013 This function is called as the last routine in phase 1 initialization. 02014 It frees memory used by the OsLoader. 02015 02016 Arguments: 02017 02018 LoadBlock - Supplies a pointer the system loader block. 02019 02020 Return Value: 02021 02022 None. 02023 02024 Environment: 02025 02026 Kernel Mode Only. System initialization. 02027 02028 --*/ 02029 02030 { 02031 02032 PLIST_ENTRY NextMd; 02033 PMMPTE Pde; 02034 PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor; 02035 MEMORY_ALLOCATION_DESCRIPTOR SavedDescriptor[MM_MAX_LOADER_BLOCKS]; 02036 PFN_NUMBER i; 02037 PFN_NUMBER NextPhysicalPage; 02038 PMMPFN Pfn1; 02039 LONG BlockNumber = -1; 02040 KIRQL OldIrql; 02041 02042 // 02043 // 02044 // Walk through the memory descriptors and add pages to the 02045 // free list in the PFN database. 02046 // 02047 02048 NextMd = LoaderBlock->MemoryDescriptorListHead.Flink; 02049 02050 while (NextMd != &LoaderBlock->MemoryDescriptorListHead) { 02051 02052 MemoryDescriptor = CONTAINING_RECORD(NextMd, 02053 MEMORY_ALLOCATION_DESCRIPTOR, 02054 ListEntry); 02055 02056 02057 switch (MemoryDescriptor->MemoryType) { 02058 case LoaderOsloaderHeap: 02059 case LoaderRegistryData: 02060 case LoaderNlsData: 02061 //case LoaderMemoryData: //this has page table and other stuff. 02062 02063 // 02064 // Capture the data to temporary storage so we won't 02065 // free memory we are referencing. Coalesce it if 02066 // the blocks are adjacent and of the same type. 02067 // 02068 02069 if (BlockNumber != -1 && 02070 MemoryDescriptor->MemoryType == SavedDescriptor[BlockNumber].MemoryType && 02071 MemoryDescriptor->BasePage == SavedDescriptor[BlockNumber].BasePage + SavedDescriptor[BlockNumber].PageCount) { 02072 02073 // 02074 // these blocks are adjacent - merge them 02075 // 02076 02077 SavedDescriptor[BlockNumber].PageCount += MemoryDescriptor->PageCount; 02078 } 02079 else { 02080 BlockNumber += 1; 02081 if (BlockNumber >= MM_MAX_LOADER_BLOCKS) { 02082 KeBugCheckEx (MEMORY_MANAGEMENT, 0, 0, 0, 0); 02083 } 02084 SavedDescriptor[BlockNumber] = *MemoryDescriptor; 02085 } 02086 02087 break; 02088 02089 default: 02090 02091 break; 02092 } 02093 02094 NextMd = MemoryDescriptor->ListEntry.Flink; 02095 } 02096 02097 LOCK_PFN (OldIrql); 02098 02099 while (BlockNumber >= 0) { 02100 02101 i = SavedDescriptor[BlockNumber].PageCount; 02102 NextPhysicalPage = SavedDescriptor[BlockNumber].BasePage; 02103 02104 Pfn1 = MI_PFN_ELEMENT (NextPhysicalPage); 02105 while (i != 0) { 02106 02107 if (Pfn1->u3.e2.ReferenceCount == 0) { 02108 if (Pfn1->u1.Flink == 0) { 02109 02110 // 02111 // Set the PTE address to the physical page for 02112 // virtual address alignment checking. 02113 // 02114 02115 Pfn1->PteAddress = 02116 (PMMPTE)(NextPhysicalPage << PTE_SHIFT); 02117 MiInsertPageInList (MmPageLocationList[FreePageList], 02118 NextPhysicalPage); 02119 } 02120 } else { 02121 02122 if (NextPhysicalPage != 0) { 02123 // 02124 // Remove PTE and insert into the free list. If it is 02125 // a physical address within the PFN database, the PTE 02126 // element does not exist and therefore cannot be updated. 02127 // 02128 02129 if (!MI_IS_PHYSICAL_ADDRESS ( 02130 MiGetVirtualAddressMappedByPte (Pfn1->PteAddress))) { 02131 02132 // 02133 // Not a physical address. 02134 // 02135 02136 *(Pfn1->PteAddress) = ZeroPte; 02137 } 02138 02139 MI_SET_PFN_DELETED (Pfn1); 02140 MiDecrementShareCountOnly (NextPhysicalPage); 02141 } 02142 } 02143 02144 Pfn1++; 02145 i -= 1; 02146 NextPhysicalPage += 1; 02147 } 02148 02149 BlockNumber -= 1; 02150 } 02151 02152 // 02153 // If the kernel has been biased to allow for 3gb of user address space, 02154 // then the first 16mb of memory is doubly mapped to KSEG0_BASE and to 02155 // ALTERNATE_BASE. Therefore, the KSEG0_BASE entries must be unmapped. 02156 // 02157 02158 #if defined(_X86_) 02159 02160 if (MmVirtualBias != 0) { 02161 Pde = MiGetPdeAddress(KSEG0_BASE); 02162 MI_WRITE_INVALID_PTE (Pde, ZeroKernelPte); 02163 MI_WRITE_INVALID_PTE (Pde + 1, ZeroKernelPte); 02164 MI_WRITE_INVALID_PTE (Pde + 2, ZeroKernelPte); 02165 MI_WRITE_INVALID_PTE (Pde + 3, ZeroKernelPte); 02166 02167 #if defined(_X86PAE_) 02168 MI_WRITE_INVALID_PTE (Pde + 4, ZeroKernelPte); 02169 MI_WRITE_INVALID_PTE (Pde + 5, ZeroKernelPte); 02170 MI_WRITE_INVALID_PTE (Pde + 6, ZeroKernelPte); 02171 MI_WRITE_INVALID_PTE (Pde + 7, ZeroKernelPte); 02172 #endif 02173 02174 } 02175 02176 #endif 02177 02178 KeFlushEntireTb (TRUE, TRUE); 02179 UNLOCK_PFN (OldIrql); 02180 return; 02181 } 02182 02183 VOID 02184 MiBuildPagedPool ( 02185 VOID 02186 ) 02187 02188 /*++ 02189 02190 Routine Description: 02191 02192 This function is called to build the structures required for paged 02193 pool and initialize the pool. Once this routine is called, paged 02194 pool may be allocated. 02195 02196 Arguments: 02197 02198 None. 02199 02200 Return Value: 02201 02202 None. 02203 02204 Environment: 02205 02206 Kernel Mode Only. System initialization. 02207 02208 --*/ 02209 02210 { 02211 SIZE_T Size; 02212 PMMPTE PointerPte; 02213 PMMPTE PointerPde; 02214 PMMPTE PointerPpe; 02215 PMMPTE PointerPpeEnd; 02216 MMPTE TempPte; 02217 PMMPFN Pfn1; 02218 PFN_NUMBER PageFrameIndex; 02219 KIRQL OldIrql; 02220 ULONG i; 02221 02222 #if !defined (_WIN64) 02223 02224 // 02225 // Double map system page directory page. 02226 // 02227 02228 #if defined (_X86PAE_) 02229 02230 PointerPte = MiGetPteAddress(PDE_BASE); 02231 02232 for (i = 0 ; i < PD_PER_SYSTEM; i += 1) { 02233 MmSystemPageDirectory[i] = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 02234 Pfn1 = MI_PFN_ELEMENT(MmSystemPageDirectory[i]); 02235 Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE; 02236 PointerPte += 1; 02237 } 02238 02239 // 02240 // Was not mapped physically, map it virtually in system space. 02241 // 02242 02243 PointerPte = MiReserveSystemPtes ( 02244 PD_PER_SYSTEM, 02245 SystemPteSpace, 02246 MM_COLOR_ALIGNMENT, 02247 ((ULONG_PTR)PDE_BASE & MM_COLOR_MASK_VIRTUAL), 02248 TRUE); 02249 02250 MmSystemPagePtes = (PMMPTE)MiGetVirtualAddressMappedByPte (PointerPte); 02251 02252 TempPte = ValidKernelPde; 02253 02254 for (i = 0 ; i < PD_PER_SYSTEM; i += 1) { 02255 TempPte.u.Hard.PageFrameNumber = MmSystemPageDirectory[i]; 02256 MI_WRITE_VALID_PTE (PointerPte, TempPte); 02257 PointerPte += 1; 02258 } 02259 02260 #else 02261 02262 MmSystemPageDirectory = MI_GET_PAGE_FRAME_FROM_PTE (MiGetPteAddress(PDE_BASE)); 02263 02264 Pfn1 = MI_PFN_ELEMENT(MmSystemPageDirectory); 02265 02266 Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE; 02267 02268 MmSystemPagePtes = (PMMPTE)MiMapPageInHyperSpace (MmSystemPageDirectory, 02269 &OldIrql); 02270 MiUnmapPageInHyperSpace (OldIrql); 02271 02272 if (!MI_IS_PHYSICAL_ADDRESS(MmSystemPagePtes)) { 02273 02274 // 02275 // Was not mapped physically, map it virtually in system space. 02276 // 02277 02278 PointerPte = MiReserveSystemPtes ( 02279 1, 02280 SystemPteSpace, 02281 MM_COLOR_ALIGNMENT, 02282 ((ULONG_PTR)PDE_BASE & MM_COLOR_MASK_VIRTUAL), 02283 TRUE); 02284 TempPte = ValidKernelPde; 02285 TempPte.u.Hard.PageFrameNumber = MmSystemPageDirectory; 02286 MI_WRITE_VALID_PTE (PointerPte, TempPte); 02287 MmSystemPagePtes = (PMMPTE)MiGetVirtualAddressMappedByPte (PointerPte); 02288 } 02289 #endif 02290 02291 #endif 02292 02293 if (MmPagedPoolMaximumDesired == TRUE) { 02294 MmSizeOfPagedPoolInBytes = 02295 ((PCHAR)MmNonPagedSystemStart - (PCHAR)MmPagedPoolStart); 02296 } 02297 02298 // 02299 // A size of 0 means size the pool based on physical memory. 02300 // 02301 02302 if (MmSizeOfPagedPoolInBytes == 0) { 02303 MmSizeOfPagedPoolInBytes = 2 * MmMaximumNonPagedPoolInBytes; 02304 } 02305 02306 if (MmIsThisAnNtAsSystem()) { 02307 if ((MmNumberOfPhysicalPages > ((24*1024*1024) >> PAGE_SHIFT)) && 02308 (MmSizeOfPagedPoolInBytes < MM_MINIMUM_PAGED_POOL_NTAS)) { 02309 02310 MmSizeOfPagedPoolInBytes = MM_MINIMUM_PAGED_POOL_NTAS; 02311 } 02312 } 02313 02314 if (MmSizeOfPagedPoolInBytes > 02315 (ULONG_PTR)((PCHAR)MmNonPagedSystemStart - (PCHAR)MmPagedPoolStart)) { 02316 MmSizeOfPagedPoolInBytes = 02317 ((PCHAR)MmNonPagedSystemStart - (PCHAR)MmPagedPoolStart); 02318 } 02319 02320 Size = BYTES_TO_PAGES(MmSizeOfPagedPoolInBytes); 02321 02322 if (Size < MM_MIN_INITIAL_PAGED_POOL) { 02323 Size = MM_MIN_INITIAL_PAGED_POOL; 02324 } 02325 02326 if (Size > (MM_MAX_PAGED_POOL >> PAGE_SHIFT)) { 02327 Size = MM_MAX_PAGED_POOL >> PAGE_SHIFT; 02328 } 02329 02330 Size = (Size + (PTE_PER_PAGE - 1)) / PTE_PER_PAGE; 02331 MmSizeOfPagedPoolInBytes = (ULONG_PTR)Size * PAGE_SIZE * PTE_PER_PAGE; 02332 02333 ASSERT ((MmSizeOfPagedPoolInBytes + (PCHAR)MmPagedPoolStart) <= 02334 (PCHAR)MmNonPagedSystemStart); 02335 02336 // 02337 // Set size to the number of pages in the pool. 02338 // 02339 02340 Size = Size * PTE_PER_PAGE; 02341 02342 MmPagedPoolEnd = (PVOID)(((PUCHAR)MmPagedPoolStart + 02343 MmSizeOfPagedPoolInBytes) - 1); 02344 02345 MmPageAlignedPoolBase[PagedPool] = MmPagedPoolStart; 02346 02347 // 02348 // Build page table page for paged pool. 02349 // 02350 02351 PointerPde = MiGetPdeAddress (MmPagedPoolStart); 02352 MmPagedPoolBasePde = PointerPde; 02353 02354 TempPte = ValidKernelPde; 02355 02356 #if defined (_WIN64) 02357 02358 // 02359 // Map in all the page directory pages to span all of paged pool. 02360 // This removes the need for a system lookup directory. 02361 // 02362 02363 PointerPpe = MiGetPpeAddress (MmPagedPoolStart); 02364 PointerPpeEnd = MiGetPpeAddress (MmPagedPoolEnd); 02365 02366 while (PointerPpe <= PointerPpeEnd) { 02367 02368 if (PointerPpe->u.Hard.Valid == 0) { 02369 PageFrameIndex = MiRemoveAnyPage( 02370 MI_GET_PAGE_COLOR_FROM_PTE (PointerPpe)); 02371 TempPte.u.Hard.PageFrameNumber = PageFrameIndex; 02372 *PointerPpe = TempPte; 02373 02374 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 02375 Pfn1->PteFrame = MI_GET_PAGE_FRAME_FROM_PTE ( 02376 MiGetPteAddress(PDE_KTBASE)); 02377 Pfn1->PteAddress = PointerPpe; 02378 Pfn1->u2.ShareCount = 1; 02379 Pfn1->u3.e2.ReferenceCount = 1; 02380 Pfn1->u3.e1.PageLocation = ActiveAndValid; 02381 Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE; 02382 } 02383 02384 PointerPpe += 1; 02385 } 02386 02387 #endif 02388 02389 PointerPte = MiGetPteAddress (MmPagedPoolStart); 02390 MmPagedPoolInfo.FirstPteForPagedPool = PointerPte; 02391 MmPagedPoolInfo.LastPteForPagedPool = MiGetPteAddress (MmPagedPoolEnd); 02392 02393 MiFillMemoryPte (PointerPde, 02394 sizeof(MMPTE) * 02395 (1 + MiGetPdeAddress (MmPagedPoolEnd) - PointerPde), 02396 MM_KERNEL_NOACCESS_PTE); 02397 02398 LOCK_PFN (OldIrql); 02399 02400 // 02401 // Map in a page table page. 02402 // 02403 02404 PageFrameIndex = MiRemoveAnyPage( 02405 MI_GET_PAGE_COLOR_FROM_PTE (PointerPde)); 02406 TempPte.u.Hard.PageFrameNumber = PageFrameIndex; 02407 MI_WRITE_VALID_PTE (PointerPde, TempPte); 02408 02409 Pfn1 = MI_PFN_ELEMENT(PageFrameIndex); 02410 #if defined (_WIN64) 02411 Pfn1->PteFrame = MI_GET_PAGE_FRAME_FROM_PTE(MiGetPpeAddress (MmPagedPoolStart)); 02412 #else 02413 #if !defined (_X86PAE_) 02414 Pfn1->PteFrame = MmSystemPageDirectory; 02415 #else 02416 Pfn1->PteFrame = MmSystemPageDirectory[(PointerPde - MiGetPdeAddress(0)) / PDE_PER_PAGE]; 02417 #endif 02418 #endif 02419 Pfn1->PteAddress = PointerPde; 02420 Pfn1->u2.ShareCount = 1; 02421 Pfn1->u3.e2.ReferenceCount = 1; 02422 Pfn1->u3.e1.PageLocation = ActiveAndValid; 02423 Pfn1->OriginalPte.u.Long = MM_DEMAND_ZERO_WRITE_PTE; 02424 MiFillMemoryPte (PointerPte, PAGE_SIZE, MM_KERNEL_NOACCESS_PTE); 02425 02426 UNLOCK_PFN (OldIrql); 02427 02428 MmPagedPoolInfo.NextPdeForPagedPoolExpansion = PointerPde + 1; 02429 02430 // 02431 // Build bitmaps for paged pool. 02432 // 02433 02434 MiCreateBitMap (&MmPagedPoolInfo.PagedPoolAllocationMap, Size, NonPagedPool); 02435 RtlSetAllBits (MmPagedPoolInfo.PagedPoolAllocationMap); 02436 02437 // 02438 // Indicate first page worth of PTEs are available. 02439 // 02440 02441 RtlClearBits (MmPagedPoolInfo.PagedPoolAllocationMap, 0, PTE_PER_PAGE); 02442 02443 MiCreateBitMap (&MmPagedPoolInfo.EndOfPagedPoolBitmap, Size, NonPagedPool); 02444 RtlClearAllBits (MmPagedPoolInfo.EndOfPagedPoolBitmap); 02445 02446 // 02447 // If verifier is present then build the verifier paged pool bitmap. 02448 // 02449 02450 if (MmVerifyDriverBufferLength != (ULONG)-1) { 02451 MiCreateBitMap (&VerifierLargePagedPoolMap, Size, NonPagedPool); 02452 RtlClearAllBits (VerifierLargePagedPoolMap); 02453 } 02454 02455 // 02456 // Initialize paged pool. 02457 // 02458 02459 InitializePool (PagedPool, 0L); 02460 02461 MiInitializeSpecialPool(); 02462 02463 // 02464 // Allow mapping of views into system space. 02465 // 02466 02467 MiInitializeSystemSpaceMap ((PVOID)0); 02468 02469 return; 02470 } 02471 02472 02473 VOID 02474 MiFindInitializationCode ( 02475 OUT PVOID *StartVa, 02476 OUT PVOID *EndVa 02477 ) 02478 02479 /*++ 02480 02481 Routine Description: 02482 02483 This function locates the start and end of the kernel initialization 02484 code. This code resides in the "init" section of the kernel image. 02485 02486 Arguments: 02487 02488 StartVa - Returns the starting address of the init section. 02489 02490 EndVa - Returns the ending address of the init section. 02491 02492 Return Value: 02493 02494 None. 02495 02496 Environment: 02497 02498 Kernel Mode Only. End of system initialization. 02499 02500 --*/ 02501 02502 { 02503 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry; 02504 PVOID CurrentBase; 02505 PVOID InitStart; 02506 PVOID InitEnd; 02507 PLIST_ENTRY Next; 02508 PIMAGE_NT_HEADERS NtHeader; 02509 PIMAGE_SECTION_HEADER SectionTableEntry; 02510 PIMAGE_SECTION_HEADER LastDiscard; 02511 LONG i; 02512 PVOID MiFindInitializationCodeAddress; 02513 02514 MiFindInitializationCodeAddress = MmGetProcedureAddress((PVOID)&MiFindInitializationCode); 02515 02516 *StartVa = NULL; 02517 02518 // 02519 // Walk through the loader blocks looking for the base which 02520 // contains this routine. 02521 // 02522 02523 KeEnterCriticalRegion(); 02524 ExAcquireResourceExclusive (&PsLoadedModuleResource, TRUE); 02525 Next = PsLoadedModuleList.Flink; 02526 02527 while ( Next != &PsLoadedModuleList ) { 02528 LdrDataTableEntry = CONTAINING_RECORD( Next, 02529 LDR_DATA_TABLE_ENTRY, 02530 InLoadOrderLinks 02531 ); 02532 if (LdrDataTableEntry->SectionPointer != NULL) { 02533 02534 // 02535 // This entry was loaded by MmLoadSystemImage so it's already 02536 // had its init section removed. 02537 // 02538 02539 Next = Next->Flink; 02540 continue; 02541 } 02542 02543 CurrentBase = (PVOID)LdrDataTableEntry->DllBase; 02544 NtHeader = RtlImageNtHeader(CurrentBase); 02545 02546 SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeader + 02547 sizeof(ULONG) + 02548 sizeof(IMAGE_FILE_HEADER) + 02549 NtHeader->FileHeader.SizeOfOptionalHeader); 02550 02551 // 02552 // From the image header, locate the section named 'INIT'. 02553 // 02554 02555 i = NtHeader->FileHeader.NumberOfSections; 02556 02557 InitStart = NULL; 02558 while (i > 0) { 02559 02560 #if DBG 02561 if ((*(PULONG)SectionTableEntry->Name == 'tini') || 02562 (*(PULONG)SectionTableEntry->Name == 'egap')) { 02563 DbgPrint("driver %wZ has lower case sections (init or pagexxx)\n", 02564 &LdrDataTableEntry->FullDllName); 02565 } 02566 #endif //DBG 02567 02568 // 02569 // Free any INIT sections (or relocation sections that haven't 02570 // been already). Note a driver may have a relocation section 02571 // but not have any INIT code. 02572 // 02573 02574 if ((*(PULONG)SectionTableEntry->Name == 'TINI') || 02575 ((SectionTableEntry->Characteristics & IMAGE_SCN_MEM_DISCARDABLE) != 0)) { 02576 02577 02578 InitStart = (PVOID)((PCHAR)CurrentBase + SectionTableEntry->VirtualAddress); 02579 InitEnd = (PVOID)((PCHAR)InitStart + SectionTableEntry->SizeOfRawData - 1); 02580 InitEnd = (PVOID)((PCHAR)PAGE_ALIGN ((PCHAR)InitEnd + 02581 (NtHeader->OptionalHeader.SectionAlignment - 1)) - 1); 02582 InitStart = (PVOID)ROUND_TO_PAGES (InitStart); 02583 02584 // 02585 // Check if more sections are discardable after this one so 02586 // even small INIT sections can be discarded. 02587 // 02588 02589 if (i == 1) { 02590 LastDiscard = SectionTableEntry; 02591 } 02592 else { 02593 LastDiscard = NULL; 02594 do { 02595 i -= 1; 02596 SectionTableEntry += 1; 02597 02598 if ((SectionTableEntry->Characteristics & 02599 IMAGE_SCN_MEM_DISCARDABLE) != 0) { 02600 02601 // 02602 // Discard this too. 02603 // 02604 02605 LastDiscard = SectionTableEntry; 02606 } else { 02607 break; 02608 } 02609 } while (i > 1); 02610 } 02611 02612 if (LastDiscard) { 02613 InitEnd = (PVOID)(((PCHAR)CurrentBase + 02614 LastDiscard->VirtualAddress) + 02615 (LastDiscard->SizeOfRawData - 1)); 02616 02617 // 02618 // If this isn't the last section in the driver then the 02619 // the next section is not discardable. So the last 02620 // section is not rounded down, but all others must be. 02621 // 02622 02623 if (i != 1) { 02624 InitEnd = (PVOID)((PCHAR)PAGE_ALIGN ((PCHAR)InitEnd + 02625 (NtHeader->OptionalHeader.SectionAlignment - 1)) - 1); 02626 } 02627 } 02628 02629 if (InitEnd > (PVOID)((PCHAR)CurrentBase + 02630 LdrDataTableEntry->SizeOfImage)) { 02631 InitEnd = (PVOID)(((ULONG_PTR)CurrentBase + 02632 (LdrDataTableEntry->SizeOfImage - 1)) | 02633 (PAGE_SIZE - 1)); 02634 } 02635 02636 if (InitStart <= InitEnd) { 02637 if ((MiFindInitializationCodeAddress >= InitStart) && 02638 (MiFindInitializationCodeAddress <= InitEnd)) { 02639 02640 // 02641 // This init section is in the kernel, don't free it 02642 // now as it would free this code! 02643 // 02644 02645 *StartVa = InitStart; 02646 *EndVa = InitEnd; 02647 } 02648 else { 02649 MiFreeInitializationCode (InitStart, InitEnd); 02650 } 02651 } 02652 } 02653 i -= 1; 02654 SectionTableEntry += 1; 02655 } 02656 Next = Next->Flink; 02657 } 02658 ExReleaseResource (&PsLoadedModuleResource); 02659 KeLeaveCriticalRegion(); 02660 return; 02661 } 02662 02663 VOID 02664 MiFreeInitializationCode ( 02665 IN PVOID StartVa, 02666 IN PVOID EndVa 02667 ) 02668 02669 /*++ 02670 02671 Routine Description: 02672 02673 This function is called to delete the initialization code. 02674 02675 Arguments: 02676 02677 StartVa - Supplies the starting address of the range to delete. 02678 02679 EndVa - Supplies the ending address of the range to delete. 02680 02681 Return Value: 02682 02683 None. 02684 02685 Environment: 02686 02687 Kernel Mode Only. Runs after system initialization. 02688 02689 --*/ 02690 02691 { 02692 PMMPFN Pfn1; 02693 PMMPTE PointerPte; 02694 PFN_NUMBER PageFrameIndex; 02695 KIRQL OldIrql; 02696 PVOID UnlockHandle; 02697 02698 UnlockHandle = MmLockPagableCodeSection((PVOID)MiFreeInitializationCode); 02699 ASSERT(UnlockHandle); 02700 02701 if (MI_IS_PHYSICAL_ADDRESS(StartVa)) { 02702 LOCK_PFN (OldIrql); 02703 while (StartVa < EndVa) { 02704 02705 // 02706 // On certain architectures (e.g., MIPS) virtual addresses 02707 // may be physical and hence have no corresponding PTE. 02708 // 02709 02710 PageFrameIndex = MI_CONVERT_PHYSICAL_TO_PFN (StartVa); 02711 02712 Pfn1 = MI_PFN_ELEMENT (PageFrameIndex); 02713 Pfn1->u2.ShareCount = 0; 02714 Pfn1->u3.e2.ReferenceCount = 0; 02715 MI_SET_PFN_DELETED (Pfn1); 02716 MiInsertPageInList (MmPageLocationList[FreePageList], PageFrameIndex); 02717 StartVa = (PVOID)((PUCHAR)StartVa + PAGE_SIZE); 02718 } 02719 UNLOCK_PFN (OldIrql); 02720 } else { 02721 PointerPte = MiGetPteAddress (StartVa); 02722 MiDeleteSystemPagableVm (PointerPte, 02723 (PFN_NUMBER) (1 + MiGetPteAddress (EndVa) - 02724 PointerPte), 02725 ZeroKernelPte, 02726 FALSE, 02727 NULL); 02728 } 02729 MmUnlockPagableImageSection(UnlockHandle); 02730 return; 02731 } 02732 02733 02734 VOID 02735 MiEnablePagingTheExecutive ( 02736 VOID 02737 ) 02738 02739 /*++ 02740 02741 Routine Description: 02742 02743 This function locates the start and end of the kernel initialization 02744 code. This code resides in the "init" section of the kernel image. 02745 02746 Arguments: 02747 02748 StartVa - Returns the starting address of the init section. 02749 02750 EndVa - Returns the ending address of the init section. 02751 02752 Return Value: 02753 02754 None. 02755 02756 Environment: 02757 02758 Kernel Mode Only. End of system initialization. 02759 02760 --*/ 02761 02762 { 02763 PLDR_DATA_TABLE_ENTRY LdrDataTableEntry; 02764 PVOID CurrentBase; 02765 PLIST_ENTRY Next; 02766 PIMAGE_NT_HEADERS NtHeader; 02767 PIMAGE_SECTION_HEADER SectionTableEntry; 02768 LONG i; 02769 PMMPTE PointerPte; 02770 PMMPTE LastPte; 02771 BOOLEAN PageSection; 02772 PVOID SectionBaseAddress; 02773 02774 // 02775 // Don't page kernel mode code if customer does not want it paged or if 02776 // this is a diskless remote boot client. 02777 // 02778 02779 if (MmDisablePagingExecutive 02780 #if defined(REMOTE_BOOT) 02781 || (IoRemoteBootClient && IoCscInitializationFailed) 02782 #endif 02783 ) { 02784 return; 02785 } 02786 02787 // 02788 // Walk through the loader blocks looking for the base which 02789 // contains this routine. 02790 // 02791 02792 KeEnterCriticalRegion(); 02793 ExAcquireResourceExclusive (&PsLoadedModuleResource, TRUE); 02794 Next = PsLoadedModuleList.Flink; 02795 while ( Next != &PsLoadedModuleList ) { 02796 LdrDataTableEntry = CONTAINING_RECORD( Next, 02797 LDR_DATA_TABLE_ENTRY, 02798 InLoadOrderLinks 02799 ); 02800 if (LdrDataTableEntry->SectionPointer != NULL) { 02801 02802 // 02803 // This entry was loaded by MmLoadSystemImage so it's already paged. 02804 // 02805 02806 Next = Next->Flink; 02807 continue; 02808 } 02809 02810 CurrentBase = (PVOID)LdrDataTableEntry->DllBase; 02811 NtHeader = RtlImageNtHeader(CurrentBase); 02812 02813 SectionTableEntry = (PIMAGE_SECTION_HEADER)((PCHAR)NtHeader + 02814 sizeof(ULONG) + 02815 sizeof(IMAGE_FILE_HEADER) + 02816 NtHeader->FileHeader.SizeOfOptionalHeader); 02817 02818 // 02819 // From the image header, locate the section named 'PAGE' or 02820 // '.edata'. 02821 // 02822 02823 i = NtHeader->FileHeader.NumberOfSections; 02824 02825 PointerPte = NULL; 02826 02827 while (i > 0) { 02828 02829 if (MI_IS_PHYSICAL_ADDRESS (CurrentBase)) { 02830 02831 // 02832 // Mapped physically, can't be paged. 02833 // 02834 02835 break; 02836 } 02837 02838 SectionBaseAddress = SECTION_BASE_ADDRESS(SectionTableEntry); 02839 02840 PageSection = ((*(PULONG)SectionTableEntry->Name == 'EGAP') || 02841 (*(PULONG)SectionTableEntry->Name == 'ade.')) && 02842 (SectionBaseAddress != 02843 ((PUCHAR)CurrentBase + SectionTableEntry->VirtualAddress)); 02844 02845 if (*(PULONG)SectionTableEntry->Name == 'EGAP' && 02846 SectionTableEntry->Name[4] == 'K' && 02847 SectionTableEntry->Name[5] == 'D') { 02848 02849 // 02850 // Only pageout PAGEKD if KdPitchDebugger is TRUE. 02851 // 02852 02853 PageSection = KdPitchDebugger; 02854 } 02855 02856 if ((*(PULONG)SectionTableEntry->Name == 'EGAP') && 02857 (*(PULONG)&SectionTableEntry->Name[4] == 'RDYH')) { 02858 02859 // 02860 // Pageout PAGEHYDRA on non Hydra systems. 02861 // 02862 02863 if (MiHydra == TRUE) { 02864 PageSection = FALSE; 02865 } 02866 } 02867 02868 if ((*(PULONG)SectionTableEntry->Name == 'EGAP') && 02869 (*(PULONG)&SectionTableEntry->Name[4] == 'YFRV')) { 02870 02871 // 02872 // Pageout PAGEVRFY if no drivers are being instrumented. 02873 // 02874 02875 if (MmVerifyDriverBufferLength != (ULONG)-1) { 02876 PageSection = FALSE; 02877 } 02878 } 02879 02880 if ((*(PULONG)SectionTableEntry->Name == 'EGAP') && 02881 (*(PULONG)&SectionTableEntry->Name[4] == 'CEPS')) { 02882 02883 // 02884 // Pageout PAGESPEC special pool code if it's not enabled. 02885 // 02886 02887 if (MiSpecialPoolPtes != 0) { 02888 PageSection = FALSE; 02889 } 02890 } 02891 02892 if (PageSection) { 02893 // 02894 // This section is pagable, save away the start and end. 02895 // 02896 02897 if (PointerPte == NULL) { 02898 02899 // 02900 // Previous section was NOT pagable, get the start address. 02901 // 02902 02903 PointerPte = MiGetPteAddress (ROUND_TO_PAGES ( 02904 (ULONG_PTR)CurrentBase + 02905 SectionTableEntry->VirtualAddress)); 02906 } 02907 LastPte = MiGetPteAddress ((ULONG_PTR)CurrentBase + 02908 SectionTableEntry->VirtualAddress + 02909 (NtHeader->OptionalHeader.SectionAlignment - 1) + 02910 SectionTableEntry->SizeOfRawData - 02911 PAGE_SIZE); 02912 02913 } else { 02914 02915 // 02916 // This section is not pagable, if the previous section was 02917 // pagable, enable it. 02918 // 02919 02920 if (PointerPte != NULL) { 02921 MiEnablePagingOfDriverAtInit (PointerPte, LastPte); 02922 PointerPte = NULL; 02923 } 02924 } 02925 i -= 1; 02926 SectionTableEntry += 1; 02927 } //end while 02928 02929 if (PointerPte != NULL) { 02930 MiEnablePagingOfDriverAtInit (PointerPte, LastPte); 02931 } 02932 02933 Next = Next->Flink; 02934 } //end while 02935 02936 ExReleaseResource (&PsLoadedModuleResource); 02937 KeLeaveCriticalRegion(); 02938 02939 return; 02940 } 02941 02942 02943 VOID 02944 MiEnablePagingOfDriverAtInit ( 02945 IN PMMPTE PointerPte, 02946 IN PMMPTE LastPte 02947 ) 02948 02949 /*++ 02950 02951 Routine Description: 02952 02953 This routine marks the specified range of PTEs as pagable. 02954 02955 Arguments: 02956 02957 PointerPte - Supplies the starting PTE. 02958 02959 LastPte - Supplies the ending PTE. 02960 02961 Return Value: 02962 02963 None. 02964 02965 --*/ 02966 02967 { 02968 PVOID Base; 02969 PFN_NUMBER PageFrameIndex; 02970 PMMPFN Pfn; 02971 MMPTE TempPte; 02972 KIRQL OldIrql; 02973 KIRQL OldIrqlWs; 02974 LOGICAL SessionAddress; 02975 02976 Base = MiGetVirtualAddressMappedByPte (PointerPte); 02977 SessionAddress = MI_IS_SESSION_PTE (PointerPte); 02978 02979 LOCK_SYSTEM_WS (OldIrqlWs); 02980 LOCK_PFN (OldIrql); 02981 02982 while (PointerPte <= LastPte) { 02983 02984 // 02985 // The PTE must be carefully checked as drivers may call MmPageEntire 02986 // during their DriverEntry yet faults may occur prior to this routine 02987 // running which cause pages to already be resident and in the working 02988 // set at this point. So checks for validity and wsindex must be 02989 // applied. 02990 // 02991 02992 if (PointerPte->u.Hard.Valid == 1) { 02993 PageFrameIndex = MI_GET_PAGE_FRAME_FROM_PTE (PointerPte); 02994 Pfn = MI_PFN_ELEMENT (PageFrameIndex); 02995 ASSERT (Pfn->u2.ShareCount == 1); 02996 02997 if (Pfn->u1.WsIndex == 0) { 02998 02999 // 03000 // Set the working set index to zero. This allows page table 03001 // pages to be brought back in with the proper WSINDEX. 03002 // 03003 03004 MI_ZERO_WSINDEX (Pfn); 03005 03006 // 03007 // Original PTE may need to be set for drivers loaded via 03008 // ntldr. 03009 // 03010 03011 if (Pfn->OriginalPte.u.Long == 0) { 03012 Pfn->OriginalPte.u.Long = MM_KERNEL_DEMAND_ZERO_PTE; 03013 #if defined(_IA64_) 03014 Pfn->OriginalPte.u.Soft.Protection |= MM_EXECUTE; 03015 #endif 03016 } 03017 03018 Pfn->u3.e1.Modified = 1; 03019 TempPte = *PointerPte; 03020 03021 MI_MAKE_VALID_PTE_TRANSITION (TempPte, 03022 Pfn->OriginalPte.u.Soft.Protection); 03023 03024 KeFlushSingleTb (Base, 03025 TRUE, 03026 TRUE, 03027 (PHARDWARE_PTE)PointerPte, 03028 TempPte.u.Flush); 03029 03030 // 03031 // Flush the translation buffer and decrement the number of valid 03032 // PTEs within the containing page table page. Note that for a 03033 // private page, the page table page is still needed because the 03034 // page is in transition. 03035 // 03036 03037 MiDecrementShareCount (PageFrameIndex); 03038 03039 MmResidentAvailablePages += 1; 03040 MmTotalSystemCodePages += 1; 03041 } 03042 else { 03043 03044 // 03045 // This would need to be taken out of the WSLEs so skip it for 03046 // now and let the normal paging algorithms remove it if we 03047 // run into memory pressure. 03048 // 03049 } 03050 03051 } 03052 Base = (PVOID)((PCHAR)Base + PAGE_SIZE); 03053 PointerPte += 1; 03054 } 03055 03056 UNLOCK_PFN (OldIrql); 03057 UNLOCK_SYSTEM_WS (OldIrqlWs); 03058 03059 if (SessionAddress == TRUE) { 03060 03061 // 03062 // Session space has no ASN - flush the entire TB. 03063 // 03064 03065 MI_FLUSH_ENTIRE_SESSION_TB (TRUE, TRUE); 03066 } 03067 03068 return; 03069 } 03070 03071 03072 MM_SYSTEMSIZE 03073 MmQuerySystemSize( 03074 VOID 03075 ) 03076 { 03077 // 03078 // 12Mb is small 03079 // 12-19 is medium 03080 // > 19 is large 03081 // 03082 return MmSystemSize; 03083 } 03084 03085 NTKERNELAPI 03086 BOOLEAN 03087 MmIsThisAnNtAsSystem( 03088 VOID 03089 ) 03090 { 03091 return (BOOLEAN)MmProductType; 03092 } 03093 03094 NTKERNELAPI 03095 VOID 03096 FASTCALL 03097 MmSetPageFaultNotifyRoutine( 03098 PPAGE_FAULT_NOTIFY_ROUTINE NotifyRoutine 03099 ) 03100 { 03101 MmPageFaultNotifyRoutine = NotifyRoutine; 03102 } 03103 03104 NTKERNELAPI 03105 VOID 03106 FASTCALL 03107 MmSetHardFaultNotifyRoutine( 03108 PHARD_FAULT_NOTIFY_ROUTINE NotifyRoutine 03109 ) 03110 { 03111 MmHardFaultNotifyRoutine = NotifyRoutine; 03112 }

Generated on Sat May 15 19:40:50 2004 for test by doxygen 1.3.7