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

sysptes.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 sysptes.c 00008 00009 Abstract: 00010 00011 This module contains the routines which reserve and release 00012 system wide PTEs reserved within the non paged portion of the 00013 system space. These PTEs are used for mapping I/O devices 00014 and mapping kernel stacks for threads. 00015 00016 Author: 00017 00018 Lou Perazzoli (loup) 6-Apr-1989 00019 00020 Revision History: 00021 00022 --*/ 00023 00024 #include "mi.h" 00025 00026 VOID 00027 MiFeedSysPtePool ( 00028 IN ULONG Index 00029 ); 00030 00031 PMMPTE 00032 MiReserveSystemPtes2 ( 00033 IN ULONG NumberOfPtes, 00034 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType, 00035 IN ULONG Alignment, 00036 IN ULONG Offset, 00037 IN ULONG BugCheckOnFailure 00038 ); 00039 00040 ULONG 00041 MiGetSystemPteListCount ( 00042 IN ULONG ListSize 00043 ); 00044 00045 #ifdef ALLOC_PRAGMA 00046 #pragma alloc_text(INIT,MiInitializeSystemPtes) 00047 #pragma alloc_text(INIT,MiAddSystemPtes) 00048 #pragma alloc_text(MISYSPTE,MiReserveSystemPtes) 00049 #pragma alloc_text(MISYSPTE,MiReserveSystemPtes2) 00050 #pragma alloc_text(MISYSPTE,MiFeedSysPtePool) 00051 #pragma alloc_text(MISYSPTE,MiReleaseSystemPtes) 00052 #pragma alloc_text(MISYSPTE,MiGetSystemPteListCount) 00053 #endif 00054 00055 #ifdef _MI_GUARD_PTE_ 00056 #define _MI_SYSPTE_DEBUG_ 1 00057 #endif 00058 00059 #ifdef _MI_SYSPTE_DEBUG_ 00060 typedef struct _MMPTE_TRACKER { 00061 USHORT NumberOfPtes; 00062 BOOLEAN InUse; 00063 BOOLEAN Reserved; 00064 } MMPTE_TRACKER, *PMMPTE_TRACKER; 00065 00066 PMMPTE_TRACKER MiPteTracker; 00067 #endif 00068 00069 ULONG MmTotalFreeSystemPtes[MaximumPtePoolTypes]; 00070 PMMPTE MmSystemPtesStart[MaximumPtePoolTypes]; 00071 PMMPTE MmSystemPtesEnd[MaximumPtePoolTypes]; 00072 00073 #define MM_MIN_SYSPTE_FREE 500 00074 #define MM_MAX_SYSPTE_FREE 3000 00075 00076 PMMPTE MmFlushPte1; 00077 00078 ULONG MmFlushCounter; 00079 00080 // 00081 // PTEs are binned at sizes 1, 2, 4, 8, and 16. 00082 // 00083 00084 #ifdef _ALPHA_ 00085 00086 // 00087 // Alpha has an 8k page size and stacks consume 9 pages (including guard page). 00088 // 00089 00090 ULONG MmSysPteIndex[MM_SYS_PTE_TABLES_MAX] = {1,2,4,9,16}; 00091 00092 UCHAR MmSysPteTables[17] = {0,0,1,2,2,3,3,3,3,3,4,4,4,4,4,4,4}; 00093 00094 #else 00095 00096 ULONG MmSysPteIndex[MM_SYS_PTE_TABLES_MAX] = {1,2,4,8,16}; 00097 00098 UCHAR MmSysPteTables[17] = {0,0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4}; 00099 #endif 00100 00101 MMPTE MmFreeSysPteListBySize [MM_SYS_PTE_TABLES_MAX]; 00102 PMMPTE MmLastSysPteListBySize [MM_SYS_PTE_TABLES_MAX]; 00103 ULONG MmSysPteListBySizeCount [MM_SYS_PTE_TABLES_MAX]; 00104 ULONG MmSysPteMinimumFree [MM_SYS_PTE_TABLES_MAX] = {100,50,30,20,20}; 00105 00106 // 00107 // Initial sizes for PTE lists. 00108 // 00109 00110 #define MM_PTE_LIST_1 400 00111 #define MM_PTE_LIST_2 100 00112 #define MM_PTE_LIST_4 60 00113 #define MM_PTE_LIST_8 50 00114 #define MM_PTE_LIST_16 40 00115 00116 #define MM_PTE_TABLE_LIMIT 16 00117 00118 PMMPTE 00119 MiReserveSystemPtes2 ( 00120 IN ULONG NumberOfPtes, 00121 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType, 00122 IN ULONG Alignment, 00123 IN ULONG Offset, 00124 IN ULONG BugCheckOnFailure 00125 ); 00126 00127 VOID 00128 MiFeedSysPtePool ( 00129 IN ULONG Index 00130 ); 00131 00132 VOID 00133 MiDumpSystemPtes ( 00134 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType 00135 ); 00136 00137 ULONG 00138 MiCountFreeSystemPtes ( 00139 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType 00140 ); 00141 00142 PVOID 00143 MiGetHighestPteConsumer ( 00144 OUT PULONG_PTR NumberOfPtes 00145 ); 00146 00147 #ifdef _MI_SYSPTE_DEBUG_ 00148 ULONG MiPtesChecked[0x10]; 00149 00150 00151 VOID 00152 MiValidateSystemPtes ( 00153 IN PMMPTE StartingPte, 00154 IN ULONG NumberOfPtes 00155 ) 00156 00157 /*++ 00158 00159 Routine Description: 00160 00161 This function validates the PTE range passed in, guaranteeing that it 00162 doesn't overlap with any free system PTEs. This enables us to catch 00163 callers that are freeing one too many PTEs. 00164 00165 Arguments: 00166 00167 StartingPte - Supplies the first PTE being freed. 00168 00169 NumberOfPtes - Supplies the number of PTEs being freed. 00170 00171 Return Value: 00172 00173 None. 00174 00175 Environment: 00176 00177 Kernel mode, DISPATCH_LEVEL or below. 00178 00179 --*/ 00180 00181 { 00182 KIRQL OldIrql; 00183 ULONG Index; 00184 PMMPTE EndingPte; 00185 PMMPTE PointerPte1; 00186 PMMPTE PointerFreedPte; 00187 ULONG PtesInThisBucket; 00188 ULONG j; 00189 00190 ASSERT (NumberOfPtes != 0); 00191 00192 EndingPte = StartingPte + NumberOfPtes - 1; 00193 00194 MiLockSystemSpace(OldIrql); 00195 00196 for (Index = 0; Index < MM_SYS_PTE_TABLES_MAX; Index += 1) { 00197 00198 PointerPte1 = &MmFreeSysPteListBySize[Index]; 00199 00200 while (PointerPte1->u.List.NextEntry != MM_EMPTY_PTE_LIST) { 00201 00202 MiPtesChecked[0] += 1; 00203 00204 PointerPte1 = MmSystemPteBase + PointerPte1->u.List.NextEntry; 00205 00206 PtesInThisBucket = MmSysPteIndex[Index]; 00207 00208 if (StartingPte >= PointerPte1 && StartingPte < PointerPte1 + PtesInThisBucket) { 00209 DbgPrint("MiValidateSystemPtes1: %x %x %x %x %x %x\n", 00210 StartingPte, 00211 EndingPte, 00212 NumberOfPtes, 00213 PointerPte1, 00214 PtesInThisBucket, 00215 Index); 00216 DbgBreakPoint (); 00217 } 00218 00219 if (EndingPte >= PointerPte1 && EndingPte < PointerPte1 + PtesInThisBucket) { 00220 DbgPrint("MiValidateSystemPtes2: %x %x %x %x %x %x\n", 00221 StartingPte, 00222 EndingPte, 00223 NumberOfPtes, 00224 PointerPte1, 00225 PtesInThisBucket, 00226 Index); 00227 DbgBreakPoint (); 00228 } 00229 00230 if (StartingPte < PointerPte1 && EndingPte >= PointerPte1 + PtesInThisBucket) { 00231 DbgPrint("MiValidateSystemPtes3: %x %x %x %x %x %x\n", 00232 StartingPte, 00233 EndingPte, 00234 NumberOfPtes, 00235 PointerPte1, 00236 PtesInThisBucket, 00237 Index); 00238 DbgBreakPoint (); 00239 } 00240 00241 PointerFreedPte = PointerPte1; 00242 for (j = 0; j < MmSysPteIndex[Index]; j++) { 00243 ASSERT (PointerFreedPte->u.Hard.Valid == 0); 00244 PointerFreedPte += 1; 00245 MiPtesChecked[1] += 1; 00246 } 00247 } 00248 } 00249 00250 MiUnlockSystemSpace(OldIrql); 00251 } 00252 00253 00254 VOID 00255 MiCheckPteAllocation ( 00256 IN PMMPTE StartingPte, 00257 IN ULONG NumberOfPtes, 00258 IN ULONG CallerId, 00259 IN ULONG Context1 00260 ) 00261 00262 /*++ 00263 00264 Routine Description: 00265 00266 This function validates the PTE range passed in, guaranteeing that it 00267 is not already allocated. 00268 00269 Arguments: 00270 00271 StartingPte - Supplies the first PTE being allocated. 00272 00273 NumberOfPtes - Supplies the number of PTEs being allocated. 00274 00275 CallerId - Supplies the caller's ID. 00276 00277 Context1 - Opaque. 00278 00279 Return Value: 00280 00281 None. 00282 00283 Environment: 00284 00285 Kernel mode, MmSystemSpaceLock held. 00286 00287 --*/ 00288 00289 { 00290 ULONG i; 00291 ULONG_PTR Index; 00292 PMMPTE BasePte; 00293 PMMPTE_TRACKER Tracker; 00294 00295 // 00296 // Don't track nonpaged pool expansion. 00297 // 00298 00299 if (StartingPte < MmSystemPtesStart[SystemPteSpace] || 00300 StartingPte + NumberOfPtes > MmSystemPtesEnd[SystemPteSpace] + 1) { 00301 return; 00302 } 00303 00304 if (MiPteTracker == NULL) { 00305 return; 00306 } 00307 00308 Index = StartingPte - MmSystemPtesStart[SystemPteSpace]; 00309 00310 Tracker = &MiPteTracker[Index]; 00311 00312 for (i = 0; i < NumberOfPtes; i += 1) { 00313 00314 if (Tracker->InUse == TRUE) { 00315 KeBugCheckEx (SYSTEM_PTE_MISUSE, 00316 7, 00317 (ULONG_PTR)StartingPte, 00318 NumberOfPtes, 00319 CallerId); 00320 } 00321 00322 Tracker += 1; 00323 } 00324 00325 Tracker = &MiPteTracker[Index]; 00326 00327 ASSERT (NumberOfPtes < 0x10000); 00328 00329 Tracker->NumberOfPtes = (USHORT)NumberOfPtes; 00330 00331 for (i = 0; i < NumberOfPtes; i += 1) { 00332 Tracker->InUse = TRUE; 00333 Tracker += 1; 00334 } 00335 00336 MiPtesChecked[0xE] += 1; 00337 } 00338 00339 00340 VOID 00341 MiCheckPteRelease ( 00342 IN PMMPTE StartingPte, 00343 IN ULONG NumberOfPtes 00344 ) 00345 00346 /*++ 00347 00348 Routine Description: 00349 00350 This function validates the PTE range passed in, guaranteeing that it 00351 is not already free. 00352 00353 Arguments: 00354 00355 StartingPte - Supplies the first PTE being allocated. 00356 00357 NumberOfPtes - Supplies the number of PTEs being allocated. 00358 00359 Return Value: 00360 00361 None. 00362 00363 Environment: 00364 00365 Kernel mode, MmSystemSpaceLock held. 00366 00367 --*/ 00368 00369 { 00370 ULONG i; 00371 ULONG_PTR Index; 00372 PMMPTE BasePte; 00373 PMMPTE_TRACKER Tracker; 00374 00375 // 00376 // Don't track nonpaged pool expansion. 00377 // 00378 00379 if (StartingPte < MmSystemPtesStart[SystemPteSpace] || 00380 StartingPte + NumberOfPtes > MmSystemPtesEnd[SystemPteSpace] + 1) { 00381 return; 00382 } 00383 00384 if (MiPteTracker == NULL) { 00385 return; 00386 } 00387 00388 ASSERT (NumberOfPtes < 0x10000); 00389 00390 Index = StartingPte - MmSystemPtesStart[SystemPteSpace]; 00391 00392 Tracker = &MiPteTracker[Index]; 00393 00394 if ((NumberOfPtes == 0) || 00395 (Tracker->NumberOfPtes != NumberOfPtes)) { 00396 KeBugCheckEx (SYSTEM_PTE_MISUSE, 00397 8, 00398 (ULONG_PTR)StartingPte, 00399 NumberOfPtes, 00400 Tracker->NumberOfPtes); 00401 } 00402 00403 Tracker->NumberOfPtes = 0; 00404 00405 for (i = 0; i < NumberOfPtes; i += 1) { 00406 00407 if (Tracker->InUse == FALSE) { 00408 KeBugCheckEx (SYSTEM_PTE_MISUSE, 00409 9, 00410 (ULONG_PTR)StartingPte, 00411 NumberOfPtes, 00412 i); 00413 } 00414 00415 Tracker += 1; 00416 } 00417 00418 Tracker = &MiPteTracker[Index]; 00419 00420 for (i = 0; i < NumberOfPtes; i += 1) { 00421 Tracker->InUse = FALSE; 00422 Tracker += 1; 00423 } 00424 00425 MiPtesChecked[0xF] += 1; 00426 } 00427 00428 00429 VOID 00430 MiRebuildPteTracker ( 00431 IN PMMPTE StartingPte, 00432 IN ULONG NumberOfPtes 00433 ) 00434 00435 /*++ 00436 00437 Routine Description: 00438 00439 This function resizes the PTE tracking data structures to account for 00440 system PTE table growth. 00441 00442 Note that the original PTE tracker structure cannot be freed unless 00443 MiFreePoolPages is modified to deal with the boundary allocations being 00444 freed - since this never happens in a normal system, there are no bounds 00445 checks in place and it will coalesce past the ends of pool. 00446 00447 Arguments: 00448 00449 StartingPte - Supplies the first PTE for the system PTE pool. 00450 00451 NumberOfPtes - Supplies the number of PTEs in the system PTE pool. 00452 00453 Return Value: 00454 00455 None. 00456 00457 Environment: 00458 00459 Kernel mode, MmSystemSpaceLock held. 00460 00461 --*/ 00462 00463 { 00464 KIRQL OldIrql; 00465 ULONG_PTR OldPtes; 00466 ULONG_PTR NewPtes; 00467 PMMPTE_TRACKER OldTracker; 00468 PMMPTE_TRACKER NewTracker; 00469 00470 // 00471 // If we've already discovered a discontiguity don't coalesce now. 00472 // 00473 00474 if (MiPteTracker == (PMMPTE_TRACKER) 0) { 00475 return; 00476 } 00477 00478 if (StartingPte + NumberOfPtes != MmSystemPtesStart[SystemPteSpace]) { 00479 #if 0 00480 MiFreePoolPages ((PVOID)MiPteTracker); 00481 #endif 00482 MiPteTracker = (PMMPTE_TRACKER) 0; 00483 return; 00484 } 00485 00486 if (MiPteTracker) { 00487 OldPtes = MmSystemPtesEnd[SystemPteSpace] - MmSystemPtesStart[SystemPteSpace] + 1; 00488 00489 NewPtes = OldPtes + NumberOfPtes; 00490 00491 NewTracker = (PMMPTE_TRACKER) ExAllocatePoolWithTag ( 00492 NonPagedPool, 00493 (ULONG_PTR)(NewPtes * sizeof (MMPTE_TRACKER)), 00494 ' mM'); 00495 00496 if (NewTracker == (PMMPTE_TRACKER) 0) { 00497 MiPteTracker = (PMMPTE_TRACKER) 0; 00498 return; 00499 } 00500 00501 RtlZeroMemory (NewTracker, NewPtes * sizeof (MMPTE_TRACKER)); 00502 00503 OldTracker = MiPteTracker; 00504 00505 MiLockSystemSpace(OldIrql); 00506 00507 RtlCopyMemory (NewTracker + NumberOfPtes, OldTracker, OldPtes * sizeof (MMPTE_TRACKER)); 00508 00509 MiPteTracker = NewTracker; 00510 00511 MiUnlockSystemSpace(OldIrql); 00512 00513 #if 0 00514 MiFreePoolPages ((PVOID)OldTracker); 00515 #endif 00516 00517 MiPtesChecked[0xD] += 1; 00518 } 00519 } 00520 #endif 00521 00522 00523 PMMPTE 00524 MiReserveSystemPtes ( 00525 IN ULONG NumberOfPtes, 00526 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType, 00527 IN ULONG Alignment, 00528 IN ULONG Offset, 00529 IN ULONG BugCheckOnFailure 00530 ) 00531 00532 /*++ 00533 00534 Routine Description: 00535 00536 This function locates the specified number of unused PTEs to locate 00537 within the non paged portion of system space. 00538 00539 Arguments: 00540 00541 NumberOfPtes - Supplies the number of PTEs to locate. 00542 00543 SystemPtePoolType - Supplies the PTE type of the pool to expand, one of 00544 SystemPteSpace or NonPagedPoolExpansion. 00545 00546 Alignment - Supplies the virtual address alignment for the address 00547 the returned PTE maps. For example, if the value is 64K, 00548 the returned PTE will map an address on a 64K boundary. 00549 An alignment of zero means to align on a page boundary. 00550 00551 Offset - Supplies the offset into the alignment for the virtual address. 00552 For example, if the Alignment is 64k and the Offset is 4k, 00553 the returned address will be 4k above a 64k boundary. 00554 00555 BugCheckOnFailure - Supplies FALSE if NULL should be returned if 00556 the request cannot be satisfied, TRUE if 00557 a bugcheck should be issued. 00558 00559 Return Value: 00560 00561 Returns the address of the first PTE located. 00562 NULL if no system PTEs can be located and BugCheckOnFailure is FALSE. 00563 00564 Environment: 00565 00566 Kernel mode, DISPATCH_LEVEL or below. 00567 00568 --*/ 00569 00570 { 00571 PMMPTE PointerPte; 00572 PMMPTE Previous; 00573 KIRQL OldIrql; 00574 ULONG PteMask; 00575 ULONG MaskSize; 00576 ULONG Index; 00577 00578 #ifdef _MI_GUARD_PTE_ 00579 ULONG ExactPtes; 00580 00581 if (NumberOfPtes == 0) { 00582 KeBugCheckEx (SYSTEM_PTE_MISUSE, 00583 0xA, 00584 BugCheckOnFailure, 00585 NumberOfPtes, 00586 SystemPtePoolType); 00587 } 00588 00589 if (SystemPtePoolType == SystemPteSpace) { 00590 NumberOfPtes += 1; 00591 } 00592 00593 ExactPtes = NumberOfPtes; 00594 #endif 00595 00596 if (SystemPtePoolType == SystemPteSpace) { 00597 00598 MaskSize = (Alignment - 1) >> (PAGE_SHIFT - PTE_SHIFT); 00599 PteMask = MaskSize & (Offset >> (PAGE_SHIFT - PTE_SHIFT)); 00600 00601 // 00602 // Acquire the system space lock to synchronize access to this 00603 // routine. 00604 // 00605 00606 MiLockSystemSpace(OldIrql); 00607 00608 if (NumberOfPtes <= MM_PTE_TABLE_LIMIT) { 00609 Index = MmSysPteTables [NumberOfPtes]; 00610 ASSERT (NumberOfPtes <= MmSysPteIndex[Index]); 00611 PointerPte = &MmFreeSysPteListBySize[Index]; 00612 #if DBG 00613 if (MmDebug & MM_DBG_SYS_PTES) { 00614 PMMPTE PointerPte1; 00615 PointerPte1 = &MmFreeSysPteListBySize[Index]; 00616 while (PointerPte1->u.List.NextEntry != MM_EMPTY_PTE_LIST) { 00617 PMMPTE PointerFreedPte; 00618 ULONG j; 00619 00620 PointerPte1 = MmSystemPteBase + PointerPte1->u.List.NextEntry; 00621 PointerFreedPte = PointerPte1; 00622 for (j = 0; j < MmSysPteIndex[Index]; j++) { 00623 ASSERT (PointerFreedPte->u.Hard.Valid == 0); 00624 PointerFreedPte++; 00625 } 00626 } 00627 } 00628 #endif //DBG 00629 00630 Previous = PointerPte; 00631 00632 while (PointerPte->u.List.NextEntry != MM_EMPTY_PTE_LIST) { 00633 00634 // 00635 // Try to find suitable PTEs with the proper alignment. 00636 // 00637 00638 Previous = PointerPte; 00639 PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry; 00640 #if !defined(_IA64_) 00641 if (PointerPte == MmFlushPte1) { 00642 KeFlushEntireTb (TRUE, TRUE); 00643 MmFlushCounter = (MmFlushCounter + 1) & MM_FLUSH_COUNTER_MASK; 00644 MmFlushPte1 = NULL; 00645 } 00646 #endif 00647 if ((Alignment == 0) || 00648 (((ULONG_PTR)PointerPte & MaskSize) == PteMask)) { 00649 00650 #ifdef _MI_SYSPTE_DEBUG_ 00651 MiCheckPteAllocation (PointerPte, 00652 NumberOfPtes, 00653 0, 00654 MmSysPteIndex[Index]); 00655 #endif 00656 // 00657 // Proper alignment and offset, update list index. 00658 // 00659 00660 ASSERT ((PointerPte->u.List.NextEntry + MmSystemPteBase) >= 00661 MmSystemPtesStart[SystemPtePoolType] || 00662 PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST); 00663 ASSERT ((PointerPte->u.List.NextEntry + MmSystemPteBase) <= 00664 MmSystemPtesEnd[SystemPtePoolType] || 00665 PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST); 00666 00667 Previous->u.List.NextEntry = PointerPte->u.List.NextEntry; 00668 MmSysPteListBySizeCount [Index] -= 1; 00669 00670 #if !defined(_IA64_) 00671 if (NumberOfPtes != 1) { 00672 00673 // 00674 // Check to see if the TB should be flushed. 00675 // 00676 00677 if ((PointerPte + 1)->u.List.NextEntry == MmFlushCounter) { 00678 KeFlushEntireTb (TRUE, TRUE); 00679 MmFlushCounter = (MmFlushCounter + 1) & 00680 MM_FLUSH_COUNTER_MASK; 00681 MmFlushPte1 = NULL; 00682 } 00683 } 00684 #endif 00685 if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) { 00686 MmLastSysPteListBySize[Index] = Previous; 00687 } 00688 #if DBG 00689 00690 if (MmDebug & MM_DBG_SYS_PTES) { 00691 PMMPTE PointerPte1; 00692 PointerPte1 = &MmFreeSysPteListBySize[Index]; 00693 while (PointerPte1->u.List.NextEntry != MM_EMPTY_PTE_LIST) { 00694 PMMPTE PointerFreedPte; 00695 ULONG j; 00696 00697 PointerPte1 = MmSystemPteBase + PointerPte1->u.List.NextEntry; 00698 PointerFreedPte = PointerPte1; 00699 for (j = 0; j < MmSysPteIndex[Index]; j++) { 00700 ASSERT (PointerFreedPte->u.Hard.Valid == 0); 00701 PointerFreedPte++; 00702 } 00703 } 00704 } 00705 #endif //DBG 00706 MiUnlockSystemSpace(OldIrql); 00707 00708 #if DBG 00709 PointerPte->u.List.NextEntry = 0xABCDE; 00710 if (MmDebug & MM_DBG_SYS_PTES) { 00711 00712 PMMPTE PointerFreedPte; 00713 ULONG j; 00714 00715 PointerFreedPte = PointerPte; 00716 for (j = 0; j < MmSysPteIndex[Index]; j++) { 00717 ASSERT (PointerFreedPte->u.Hard.Valid == 0); 00718 PointerFreedPte++; 00719 } 00720 } 00721 if (PointerPte < MmSystemPtesStart[SystemPtePoolType]) { 00722 KeBugCheckEx (SYSTEM_PTE_MISUSE, 00723 0xB, 00724 (ULONG_PTR)PointerPte, 00725 NumberOfPtes, 00726 SystemPtePoolType); 00727 } 00728 if (PointerPte > MmSystemPtesEnd[SystemPtePoolType]) { 00729 KeBugCheckEx (SYSTEM_PTE_MISUSE, 00730 0xC, 00731 (ULONG_PTR)PointerPte, 00732 NumberOfPtes, 00733 SystemPtePoolType); 00734 } 00735 #endif //DBG 00736 00737 if (MmSysPteListBySizeCount[Index] < 00738 MmSysPteMinimumFree[Index]) { 00739 MiFeedSysPtePool (Index); 00740 } 00741 #ifdef _MI_GUARD_PTE_ 00742 (PointerPte + ExactPtes - 1)->u.Long = MM_KERNEL_NOACCESS_PTE; 00743 #endif 00744 return PointerPte; 00745 } 00746 } 00747 NumberOfPtes = MmSysPteIndex [Index]; 00748 } 00749 MiUnlockSystemSpace(OldIrql); 00750 } 00751 00752 #ifdef _MI_GUARD_PTE_ 00753 NumberOfPtes = ExactPtes; 00754 #endif 00755 00756 PointerPte = MiReserveSystemPtes2 (NumberOfPtes, 00757 SystemPtePoolType, 00758 Alignment, 00759 Offset, 00760 BugCheckOnFailure); 00761 00762 #if DBG 00763 if (MmDebug & MM_DBG_SYS_PTES) { 00764 00765 PMMPTE PointerFreedPte; 00766 ULONG j; 00767 00768 if (PointerPte) { 00769 PointerFreedPte = PointerPte; 00770 for (j = 0; j < NumberOfPtes; j++) { 00771 ASSERT (PointerFreedPte->u.Hard.Valid == 0); 00772 PointerFreedPte++; 00773 } 00774 } 00775 } 00776 #endif //DBG 00777 00778 #ifdef _MI_GUARD_PTE_ 00779 if (PointerPte) { 00780 (PointerPte + ExactPtes - 1)->u.Long = MM_KERNEL_NOACCESS_PTE; 00781 } 00782 #endif 00783 00784 return PointerPte; 00785 } 00786 00787 VOID 00788 MiFeedSysPtePool ( 00789 IN ULONG Index 00790 ) 00791 00792 /*++ 00793 00794 Routine Description: 00795 00796 This routine adds PTEs to the look aside lists. 00797 00798 Arguments: 00799 00800 Index - Supplies the index for the look aside list to fill. 00801 00802 Return Value: 00803 00804 None. 00805 00806 00807 Environment: 00808 00809 Kernel mode, internal to SysPtes. 00810 00811 --*/ 00812 00813 { 00814 #ifdef _MI_GUARD_PTE_ 00815 UNREFERENCED_PARAMETER (Index); 00816 #else 00817 ULONG i; 00818 PMMPTE PointerPte; 00819 00820 if (MmTotalFreeSystemPtes[SystemPteSpace] < MM_MIN_SYSPTE_FREE) { 00821 return; 00822 } 00823 00824 for (i = 0; i < 10 ; i++ ) { 00825 PointerPte = MiReserveSystemPtes2 (MmSysPteIndex [Index], 00826 SystemPteSpace, 00827 0, 00828 0, 00829 FALSE); 00830 if (PointerPte == NULL) { 00831 return; 00832 } 00833 MiReleaseSystemPtes (PointerPte, 00834 MmSysPteIndex [Index], 00835 SystemPteSpace); 00836 } 00837 #endif 00838 return; 00839 } 00840 00841 00842 PMMPTE 00843 MiReserveSystemPtes2 ( 00844 IN ULONG NumberOfPtes, 00845 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType, 00846 IN ULONG Alignment, 00847 IN ULONG Offset, 00848 IN ULONG BugCheckOnFailure 00849 ) 00850 00851 /*++ 00852 00853 Routine Description: 00854 00855 This function locates the specified number of unused PTEs to locate 00856 within the non paged portion of system space. 00857 00858 Arguments: 00859 00860 NumberOfPtes - Supplies the number of PTEs to locate. 00861 00862 SystemPtePoolType - Supplies the PTE type of the pool to expand, one of 00863 SystemPteSpace or NonPagedPoolExpansion. 00864 00865 Alignment - Supplies the virtual address alignment for the address 00866 the returned PTE maps. For example, if the value is 64K, 00867 the returned PTE will map an address on a 64K boundary. 00868 An alignment of zero means to align on a page boundary. 00869 00870 Offset - Supplies the offset into the alignment for the virtual address. 00871 For example, if the Alignment is 64k and the Offset is 4k, 00872 the returned address will be 4k above a 64k boundary. 00873 00874 BugCheckOnFailure - Supplies FALSE if NULL should be returned if 00875 the request cannot be satisfied, TRUE if 00876 a bugcheck should be issued. 00877 00878 Return Value: 00879 00880 Returns the address of the first PTE located. 00881 NULL if no system PTEs can be located and BugCheckOnFailure is FALSE. 00882 00883 Environment: 00884 00885 Kernel mode, DISPATCH_LEVEL or below. 00886 00887 --*/ 00888 00889 { 00890 PMMPTE PointerPte; 00891 PMMPTE PointerFollowingPte; 00892 PMMPTE Previous; 00893 ULONG_PTR SizeInSet; 00894 KIRQL OldIrql; 00895 ULONG MaskSize; 00896 ULONG NumberOfRequiredPtes; 00897 ULONG OffsetSum; 00898 ULONG PtesToObtainAlignment; 00899 PMMPTE NextSetPointer; 00900 ULONG_PTR LeftInSet; 00901 ULONG_PTR PteOffset; 00902 MMPTE_FLUSH_LIST PteFlushList; 00903 PVOID HighConsumer; 00904 ULONG_PTR HighPteUse; 00905 00906 MaskSize = (Alignment - 1) >> (PAGE_SHIFT - PTE_SHIFT); 00907 00908 OffsetSum = (Offset >> (PAGE_SHIFT - PTE_SHIFT)) | 00909 (Alignment >> (PAGE_SHIFT - PTE_SHIFT)); 00910 00911 MiLockSystemSpace(OldIrql); 00912 00913 // 00914 // The nonpaged PTE pool uses the invalid PTEs to define the pool 00915 // structure. A global pointer points to the first free set 00916 // in the list, each free set contains the number free and a pointer 00917 // to the next free set. The free sets are kept in an ordered list 00918 // such that the pointer to the next free set is always greater 00919 // than the address of the current free set. 00920 // 00921 // As to not limit the size of this pool, two PTEs are used 00922 // to define a free region. If the region is a single PTE, the 00923 // prototype field within the PTE is set indicating the set 00924 // consists of a single PTE. 00925 // 00926 // The page frame number field is used to define the next set 00927 // and the number free. The two flavors are: 00928 // 00929 // o V 00930 // n l 00931 // e d 00932 // +-----------------------+-+----------+ 00933 // | next set |0|0 0| 00934 // +-----------------------+-+----------+ 00935 // | number in this set |0|0 0| 00936 // +-----------------------+-+----------+ 00937 // 00938 // 00939 // +-----------------------+-+----------+ 00940 // | next set |1|0 0| 00941 // +-----------------------+-+----------+ 00942 // ... 00943 // 00944 00945 // 00946 // Acquire the system space lock to synchronize access to this routine. 00947 // 00948 00949 PointerPte = &MmFirstFreeSystemPte[SystemPtePoolType]; 00950 Previous = PointerPte; 00951 00952 if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) { 00953 00954 // 00955 // End of list and none found, return NULL or bugcheck. 00956 // 00957 00958 if (BugCheckOnFailure) { 00959 goto IssueBugcheck; 00960 } 00961 00962 MiUnlockSystemSpace(OldIrql); 00963 return NULL; 00964 } 00965 00966 PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry; 00967 00968 if (Alignment <= PAGE_SIZE) { 00969 00970 // 00971 // Don't deal with alignment issues. 00972 // 00973 00974 while (TRUE) { 00975 00976 if (PointerPte->u.List.OneEntry) { 00977 SizeInSet = 1; 00978 00979 } else { 00980 00981 PointerFollowingPte = PointerPte + 1; 00982 SizeInSet = (ULONG_PTR) PointerFollowingPte->u.List.NextEntry; 00983 } 00984 00985 if (NumberOfPtes < SizeInSet) { 00986 00987 // 00988 // Get the PTEs from this set and reduce the size of the 00989 // set. Note that the size of the current set cannot be 1. 00990 // 00991 00992 if ((SizeInSet - NumberOfPtes) == 1) { 00993 00994 // 00995 // Collapse to the single PTE format. 00996 // 00997 00998 PointerPte->u.List.OneEntry = 1; 00999 01000 } else { 01001 01002 PointerFollowingPte->u.List.NextEntry = SizeInSet - NumberOfPtes; 01003 01004 // 01005 // Get the required PTEs from the end of the set. 01006 // 01007 01008 #if 0 01009 if (MmDebug & MM_DBG_SYS_PTES) { 01010 MiDumpSystemPtes(SystemPtePoolType); 01011 PointerFollowingPte = PointerPte + (SizeInSet - NumberOfPtes); 01012 DbgPrint("allocated 0x%lx Ptes at %lx\n",NumberOfPtes,PointerFollowingPte); 01013 } 01014 #endif //0 01015 } 01016 01017 MmTotalFreeSystemPtes[SystemPtePoolType] -= NumberOfPtes; 01018 #if DBG 01019 if (MmDebug & MM_DBG_SYS_PTES) { 01020 ASSERT (MmTotalFreeSystemPtes[SystemPtePoolType] == 01021 MiCountFreeSystemPtes (SystemPtePoolType)); 01022 } 01023 #endif //DBG 01024 01025 #ifdef _MI_SYSPTE_DEBUG_ 01026 MiCheckPteAllocation (PointerPte + (SizeInSet - NumberOfPtes), 01027 NumberOfPtes, 01028 1, 01029 0); 01030 #endif 01031 01032 MiUnlockSystemSpace(OldIrql); 01033 01034 PointerPte = PointerPte + (SizeInSet - NumberOfPtes); 01035 goto Flush; 01036 } 01037 01038 if (NumberOfPtes == SizeInSet) { 01039 01040 // 01041 // Satisfy the request with this complete set and change 01042 // the list to reflect the fact that this set is gone. 01043 // 01044 01045 Previous->u.List.NextEntry = PointerPte->u.List.NextEntry; 01046 01047 // 01048 // Release the system PTE lock. 01049 // 01050 01051 #if 0 01052 if (MmDebug & MM_DBG_SYS_PTES) { 01053 MiDumpSystemPtes(SystemPtePoolType); 01054 PointerFollowingPte = PointerPte + (SizeInSet - NumberOfPtes); 01055 DbgPrint("allocated 0x%lx Ptes at %lx\n",NumberOfPtes,PointerFollowingPte); 01056 } 01057 #endif //0 01058 01059 MmTotalFreeSystemPtes[SystemPtePoolType] -= NumberOfPtes; 01060 #if DBG 01061 if (MmDebug & MM_DBG_SYS_PTES) { 01062 ASSERT (MmTotalFreeSystemPtes[SystemPtePoolType] == 01063 MiCountFreeSystemPtes (SystemPtePoolType)); 01064 } 01065 #endif //DBG 01066 01067 #ifdef _MI_SYSPTE_DEBUG_ 01068 MiCheckPteAllocation (PointerPte, 01069 NumberOfPtes, 01070 2, 01071 0); 01072 #endif 01073 01074 MiUnlockSystemSpace(OldIrql); 01075 goto Flush; 01076 } 01077 01078 // 01079 // Point to the next set and try again 01080 // 01081 01082 if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) { 01083 01084 // 01085 // End of list and none found, return NULL or bugcheck. 01086 // 01087 01088 if (BugCheckOnFailure) { 01089 goto IssueBugcheck; 01090 } 01091 01092 MiUnlockSystemSpace(OldIrql); 01093 return NULL; 01094 } 01095 Previous = PointerPte; 01096 PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry; 01097 ASSERT (PointerPte > Previous); 01098 } 01099 01100 } else { 01101 01102 // 01103 // Deal with the alignment issues. 01104 // 01105 01106 while (TRUE) { 01107 01108 if (PointerPte->u.List.OneEntry) { 01109 SizeInSet = 1; 01110 01111 } else { 01112 01113 PointerFollowingPte = PointerPte + 1; 01114 SizeInSet = (ULONG_PTR) PointerFollowingPte->u.List.NextEntry; 01115 } 01116 01117 PtesToObtainAlignment = (ULONG) 01118 (((OffsetSum - ((ULONG_PTR)PointerPte & MaskSize)) & MaskSize) >> 01119 PTE_SHIFT); 01120 01121 NumberOfRequiredPtes = NumberOfPtes + PtesToObtainAlignment; 01122 01123 if (NumberOfRequiredPtes < SizeInSet) { 01124 01125 // 01126 // Get the PTEs from this set and reduce the size of the 01127 // set. Note that the size of the current set cannot be 1. 01128 // 01129 // This current block will be slit into 2 blocks if 01130 // the PointerPte does not match the alignment. 01131 // 01132 01133 // 01134 // Check to see if the first PTE is on the proper 01135 // alignment, if so, eliminate this block. 01136 // 01137 01138 LeftInSet = SizeInSet - NumberOfRequiredPtes; 01139 01140 // 01141 // Set up the new set at the end of this block. 01142 // 01143 01144 NextSetPointer = PointerPte + NumberOfRequiredPtes; 01145 NextSetPointer->u.List.NextEntry = 01146 PointerPte->u.List.NextEntry; 01147 01148 PteOffset = (ULONG_PTR)(NextSetPointer - MmSystemPteBase); 01149 01150 if (PtesToObtainAlignment == 0) { 01151 01152 Previous->u.List.NextEntry += NumberOfRequiredPtes; 01153 01154 } else { 01155 01156 // 01157 // Point to the new set at the end of the block 01158 // we are giving away. 01159 // 01160 01161 PointerPte->u.List.NextEntry = PteOffset; 01162 01163 // 01164 // Update the size of the current set. 01165 // 01166 01167 if (PtesToObtainAlignment == 1) { 01168 01169 // 01170 // Collapse to the single PTE format. 01171 // 01172 01173 PointerPte->u.List.OneEntry = 1; 01174 01175 } else { 01176 01177 // 01178 // Set the set size in the next PTE. 01179 // 01180 01181 PointerFollowingPte->u.List.NextEntry = 01182 PtesToObtainAlignment; 01183 } 01184 } 01185 01186 // 01187 // Set up the new set at the end of the block. 01188 // 01189 01190 if (LeftInSet == 1) { 01191 NextSetPointer->u.List.OneEntry = 1; 01192 } else { 01193 NextSetPointer->u.List.OneEntry = 0; 01194 NextSetPointer += 1; 01195 NextSetPointer->u.List.NextEntry = LeftInSet; 01196 } 01197 MmTotalFreeSystemPtes[SystemPtePoolType] -= NumberOfPtes; 01198 #if DBG 01199 if (MmDebug & MM_DBG_SYS_PTES) { 01200 ASSERT (MmTotalFreeSystemPtes[SystemPtePoolType] == 01201 MiCountFreeSystemPtes (SystemPtePoolType)); 01202 } 01203 #endif //DBG 01204 01205 #ifdef _MI_SYSPTE_DEBUG_ 01206 MiCheckPteAllocation (PointerPte + PtesToObtainAlignment, 01207 NumberOfPtes, 01208 3, 01209 0); 01210 #endif 01211 01212 MiUnlockSystemSpace(OldIrql); 01213 01214 PointerPte = PointerPte + PtesToObtainAlignment; 01215 goto Flush; 01216 } 01217 01218 if (NumberOfRequiredPtes == SizeInSet) { 01219 01220 // 01221 // Satisfy the request with this complete set and change 01222 // the list to reflect the fact that this set is gone. 01223 // 01224 01225 if (PtesToObtainAlignment == 0) { 01226 01227 // 01228 // This block exactly satisfies the request. 01229 // 01230 01231 Previous->u.List.NextEntry = 01232 PointerPte->u.List.NextEntry; 01233 01234 } else { 01235 01236 // 01237 // A portion at the start of this block remains. 01238 // 01239 01240 if (PtesToObtainAlignment == 1) { 01241 01242 // 01243 // Collapse to the single PTE format. 01244 // 01245 01246 PointerPte->u.List.OneEntry = 1; 01247 01248 } else { 01249 PointerFollowingPte->u.List.NextEntry = 01250 PtesToObtainAlignment; 01251 01252 } 01253 } 01254 01255 MmTotalFreeSystemPtes[SystemPtePoolType] -= NumberOfPtes; 01256 #if DBG 01257 if (MmDebug & MM_DBG_SYS_PTES) { 01258 ASSERT (MmTotalFreeSystemPtes[SystemPtePoolType] == 01259 MiCountFreeSystemPtes (SystemPtePoolType)); 01260 } 01261 #endif //DBG 01262 01263 #ifdef _MI_SYSPTE_DEBUG_ 01264 MiCheckPteAllocation (PointerPte + PtesToObtainAlignment, 01265 NumberOfPtes, 01266 4, 01267 0); 01268 #endif 01269 01270 MiUnlockSystemSpace(OldIrql); 01271 01272 PointerPte = PointerPte + PtesToObtainAlignment; 01273 goto Flush; 01274 } 01275 01276 // 01277 // Point to the next set and try again 01278 // 01279 01280 if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) { 01281 01282 // 01283 // End of list and none found, return NULL or bugcheck. 01284 // 01285 01286 if (BugCheckOnFailure) { 01287 goto IssueBugcheck; 01288 } 01289 01290 MiUnlockSystemSpace(OldIrql); 01291 return NULL; 01292 } 01293 Previous = PointerPte; 01294 PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry; 01295 ASSERT (PointerPte > Previous); 01296 } 01297 } 01298 Flush: 01299 01300 if (SystemPtePoolType == SystemPteSpace) { 01301 PVOID BaseAddress; 01302 ULONG j; 01303 01304 PteFlushList.Count = 0; 01305 Previous = PointerPte; 01306 BaseAddress = MiGetVirtualAddressMappedByPte (Previous); 01307 01308 for (j = 0; j < NumberOfPtes ; j++) { 01309 if (PteFlushList.Count != MM_MAXIMUM_FLUSH_COUNT) { 01310 PteFlushList.FlushPte[PteFlushList.Count] = Previous; 01311 PteFlushList.FlushVa[PteFlushList.Count] = BaseAddress; 01312 PteFlushList.Count += 1; 01313 } 01314 01315 // 01316 // PTEs being freed better be invalid. 01317 // 01318 ASSERT (Previous->u.Hard.Valid == 0); 01319 01320 *Previous = ZeroKernelPte; 01321 BaseAddress = (PVOID)((PCHAR)BaseAddress + PAGE_SIZE); 01322 Previous++; 01323 } 01324 01325 KeRaiseIrql (DISPATCH_LEVEL, &OldIrql); 01326 MiFlushPteList (&PteFlushList, TRUE, ZeroKernelPte); 01327 KeLowerIrql (OldIrql); 01328 } 01329 return PointerPte; 01330 01331 IssueBugcheck: 01332 01333 if (SystemPtePoolType == SystemPteSpace) { 01334 01335 HighConsumer = MiGetHighestPteConsumer (&HighPteUse); 01336 01337 if (HighConsumer != NULL) { 01338 KeBugCheckEx (DRIVER_USED_EXCESSIVE_PTES, 01339 (ULONG_PTR)HighConsumer, 01340 HighPteUse, 01341 MmTotalFreeSystemPtes[SystemPtePoolType], 01342 MmNumberOfSystemPtes); 01343 } 01344 } 01345 01346 KeBugCheckEx (NO_MORE_SYSTEM_PTES, 01347 (ULONG_PTR)SystemPtePoolType, 01348 NumberOfPtes, 01349 MmTotalFreeSystemPtes[SystemPtePoolType], 01350 MmNumberOfSystemPtes); 01351 } 01352 01353 VOID 01354 MiReleaseSystemPtes ( 01355 IN PMMPTE StartingPte, 01356 IN ULONG NumberOfPtes, 01357 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType 01358 ) 01359 01360 /*++ 01361 01362 Routine Description: 01363 01364 This function releases the specified number of PTEs 01365 within the non paged portion of system space. 01366 01367 Note that the PTEs must be invalid and the page frame number 01368 must have been set to zero. 01369 01370 Arguments: 01371 01372 StartingPte - Supplies the address of the first PTE to release. 01373 01374 NumberOfPtes - Supplies the number of PTEs to release. 01375 01376 SystemPtePoolType - Supplies the PTE type of the pool to release PTEs to, 01377 one of SystemPteSpace or NonPagedPoolExpansion. 01378 01379 Return Value: 01380 01381 none. 01382 01383 Environment: 01384 01385 Kernel mode. 01386 01387 --*/ 01388 01389 { 01390 ULONG_PTR Size; 01391 ULONG i; 01392 ULONG_PTR PteOffset; 01393 PMMPTE PointerPte; 01394 PMMPTE PointerFollowingPte; 01395 PMMPTE NextPte; 01396 KIRQL OldIrql; 01397 ULONG Index; 01398 #if defined(_IA64_) 01399 MMPTE_FLUSH_LIST PteFlushList; 01400 PMMPTE Previous; 01401 PVOID BaseAddress; 01402 #endif 01403 01404 // 01405 // Check to make sure the PTEs don't map anything. 01406 // 01407 01408 ASSERT (NumberOfPtes != 0); 01409 01410 #ifdef _MI_GUARD_PTE_ 01411 if (NumberOfPtes == 0) { 01412 KeBugCheckEx (SYSTEM_PTE_MISUSE, 01413 0xD, 01414 (ULONG_PTR)StartingPte, 01415 NumberOfPtes, 01416 SystemPtePoolType); 01417 } 01418 01419 if (SystemPtePoolType == SystemPteSpace) { 01420 if ((StartingPte + NumberOfPtes)->u.Long != MM_KERNEL_NOACCESS_PTE) { 01421 KeBugCheckEx (SYSTEM_PTE_MISUSE, 01422 0xE, 01423 (ULONG_PTR)StartingPte, 01424 NumberOfPtes, 01425 SystemPtePoolType); 01426 } 01427 NumberOfPtes += 1; 01428 } 01429 #endif 01430 01431 #if DBG 01432 if (StartingPte < MmSystemPtesStart[SystemPtePoolType]) { 01433 KeBugCheckEx (SYSTEM_PTE_MISUSE, 01434 0xF, 01435 (ULONG_PTR)StartingPte, 01436 NumberOfPtes, 01437 SystemPtePoolType); 01438 } 01439 01440 if (StartingPte > MmSystemPtesEnd[SystemPtePoolType]) { 01441 KeBugCheckEx (SYSTEM_PTE_MISUSE, 01442 0x10, 01443 (ULONG_PTR)StartingPte, 01444 NumberOfPtes, 01445 SystemPtePoolType); 01446 } 01447 #endif //DBG 01448 01449 #if 0 01450 if (MmDebug & MM_DBG_SYS_PTES) { 01451 DbgPrint("releasing 0x%lx system PTEs at location %lx\n",NumberOfPtes,StartingPte); 01452 } 01453 #endif //0 01454 01455 #if defined(_IA64_) 01456 01457 PteFlushList.Count = 0; 01458 Previous = StartingPte; 01459 BaseAddress = MiGetVirtualAddressMappedByPte (Previous); 01460 for (i = 0; i < NumberOfPtes ; i++) { 01461 if (PteFlushList.Count != MM_MAXIMUM_FLUSH_COUNT) { 01462 PteFlushList.FlushPte[PteFlushList.Count] = Previous; 01463 PteFlushList.FlushVa[PteFlushList.Count] = BaseAddress; 01464 PteFlushList.Count += 1; 01465 } 01466 *Previous = ZeroKernelPte; 01467 BaseAddress = (PVOID)((PCHAR)BaseAddress + PAGE_SIZE); 01468 Previous++; 01469 } 01470 01471 KeRaiseIrql (DISPATCH_LEVEL, &OldIrql); 01472 MiFlushPteList (&PteFlushList, TRUE, ZeroKernelPte); 01473 KeLowerIrql (OldIrql); 01474 01475 #else 01476 01477 // 01478 // Zero PTEs. 01479 // 01480 01481 #ifdef _MI_SYSPTE_DEBUG_ 01482 MiValidateSystemPtes (StartingPte, NumberOfPtes); 01483 #endif 01484 01485 MiFillMemoryPte (StartingPte, 01486 NumberOfPtes * sizeof (MMPTE), 01487 ZeroKernelPte.u.Long); 01488 01489 #ifdef _MI_SYSPTE_DEBUG_ 01490 01491 // 01492 // Invalidate any TB entries that might have been mapped to 01493 // immediately prevent bad callers from corrupting the system. 01494 // 01495 01496 KeFlushEntireTb (TRUE, TRUE); 01497 #endif 01498 01499 #endif 01500 01501 // 01502 // Acquire system space spin lock to synchronize access. 01503 // 01504 01505 PteOffset = (ULONG_PTR)(StartingPte - MmSystemPteBase); 01506 01507 #ifdef _MI_SYSPTE_DEBUG_ 01508 if (PteOffset == 0) { 01509 KeBugCheckEx (SYSTEM_PTE_MISUSE, 01510 0x11, 01511 (ULONG_PTR)StartingPte, 01512 NumberOfPtes, 01513 SystemPtePoolType); 01514 } 01515 #endif 01516 01517 MiLockSystemSpace(OldIrql); 01518 01519 #ifdef _MI_SYSPTE_DEBUG_ 01520 MiCheckPteRelease (StartingPte, NumberOfPtes); 01521 #endif 01522 01523 #ifndef _MI_GUARD_PTE_ 01524 if ((SystemPtePoolType == SystemPteSpace) && 01525 (NumberOfPtes <= MM_PTE_TABLE_LIMIT)) { 01526 01527 Index = MmSysPteTables [NumberOfPtes]; 01528 NumberOfPtes = MmSysPteIndex [Index]; 01529 01530 if (MmTotalFreeSystemPtes[SystemPteSpace] >= MM_MIN_SYSPTE_FREE) { 01531 01532 // 01533 // Don't add to the pool if the size is greater than 15 + the minimum. 01534 // 01535 01536 i = MmSysPteMinimumFree[Index]; 01537 if (MmTotalFreeSystemPtes[SystemPteSpace] >= MM_MAX_SYSPTE_FREE) { 01538 01539 // 01540 // Lots of free PTEs, quadruple the limit. 01541 // 01542 01543 i = i * 4; 01544 } 01545 i += 15; 01546 if (MmSysPteListBySizeCount[Index] <= i) { 01547 01548 #if DBG 01549 if (MmDebug & MM_DBG_SYS_PTES) { 01550 PMMPTE PointerPte1; 01551 01552 PointerPte1 = &MmFreeSysPteListBySize[Index]; 01553 while (PointerPte1->u.List.NextEntry != MM_EMPTY_PTE_LIST) { 01554 PMMPTE PointerFreedPte; 01555 ULONG j; 01556 01557 PointerPte1 = MmSystemPteBase + PointerPte1->u.List.NextEntry; 01558 PointerFreedPte = PointerPte1; 01559 for (j = 0; j < MmSysPteIndex[Index]; j++) { 01560 ASSERT (PointerFreedPte->u.Hard.Valid == 0); 01561 PointerFreedPte++; 01562 } 01563 } 01564 } 01565 #endif //DBG 01566 MmSysPteListBySizeCount [Index] += 1; 01567 PointerPte = MmLastSysPteListBySize[Index]; 01568 ASSERT (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST); 01569 PointerPte->u.List.NextEntry = PteOffset; 01570 MmLastSysPteListBySize[Index] = StartingPte; 01571 StartingPte->u.List.NextEntry = MM_EMPTY_PTE_LIST; 01572 01573 #if DBG 01574 if (MmDebug & MM_DBG_SYS_PTES) { 01575 PMMPTE PointerPte1; 01576 PointerPte1 = &MmFreeSysPteListBySize[Index]; 01577 while (PointerPte1->u.List.NextEntry != MM_EMPTY_PTE_LIST) { 01578 PMMPTE PointerFreedPte; 01579 ULONG j; 01580 01581 PointerPte1 = MmSystemPteBase + PointerPte1->u.List.NextEntry; 01582 PointerFreedPte = PointerPte1; 01583 for (j = 0; j < MmSysPteIndex[Index]; j++) { 01584 ASSERT (PointerFreedPte->u.Hard.Valid == 0); 01585 PointerFreedPte++; 01586 } 01587 } 01588 } 01589 #endif //DBG 01590 if (NumberOfPtes == 1) { 01591 if (MmFlushPte1 == NULL) { 01592 MmFlushPte1 = StartingPte; 01593 } 01594 } else { 01595 (StartingPte + 1)->u.List.NextEntry = MmFlushCounter; 01596 } 01597 01598 MiUnlockSystemSpace(OldIrql); 01599 return; 01600 } 01601 } 01602 } 01603 #endif 01604 01605 MmTotalFreeSystemPtes[SystemPtePoolType] += NumberOfPtes; 01606 01607 PteOffset = (ULONG_PTR)(StartingPte - MmSystemPteBase); 01608 PointerPte = &MmFirstFreeSystemPte[SystemPtePoolType]; 01609 01610 while (TRUE) { 01611 NextPte = MmSystemPteBase + PointerPte->u.List.NextEntry; 01612 if (PteOffset < PointerPte->u.List.NextEntry) { 01613 01614 // 01615 // Insert in the list at this point. The 01616 // previous one should point to the new freed set and 01617 // the new freed set should point to the place 01618 // the previous set points to. 01619 // 01620 // Attempt to combine the clusters before we 01621 // insert. 01622 // 01623 // Locate the end of the current structure. 01624 // 01625 01626 ASSERT (((StartingPte + NumberOfPtes) <= NextPte) || 01627 (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST)); 01628 01629 PointerFollowingPte = PointerPte + 1; 01630 if (PointerPte->u.List.OneEntry) { 01631 Size = 1; 01632 } else { 01633 Size = (ULONG_PTR) PointerFollowingPte->u.List.NextEntry; 01634 } 01635 if ((PointerPte + Size) == StartingPte) { 01636 01637 // 01638 // We can combine the clusters. 01639 // 01640 01641 NumberOfPtes += (ULONG)Size; 01642 PointerFollowingPte->u.List.NextEntry = NumberOfPtes; 01643 PointerPte->u.List.OneEntry = 0; 01644 01645 // 01646 // Point the starting PTE to the beginning of 01647 // the new free set and try to combine with the 01648 // following free cluster. 01649 // 01650 01651 StartingPte = PointerPte; 01652 01653 } else { 01654 01655 // 01656 // Can't combine with previous. Make this Pte the 01657 // start of a cluster. 01658 // 01659 01660 // 01661 // Point this cluster to the next cluster. 01662 // 01663 01664 StartingPte->u.List.NextEntry = PointerPte->u.List.NextEntry; 01665 01666 // 01667 // Point the current cluster to this cluster. 01668 // 01669 01670 PointerPte->u.List.NextEntry = PteOffset; 01671 01672 // 01673 // Set the size of this cluster. 01674 // 01675 01676 if (NumberOfPtes == 1) { 01677 StartingPte->u.List.OneEntry = 1; 01678 01679 } else { 01680 StartingPte->u.List.OneEntry = 0; 01681 PointerFollowingPte = StartingPte + 1; 01682 PointerFollowingPte->u.List.NextEntry = NumberOfPtes; 01683 } 01684 } 01685 01686 // 01687 // Attempt to combine the newly created cluster with 01688 // the following cluster. 01689 // 01690 01691 if ((StartingPte + NumberOfPtes) == NextPte) { 01692 01693 // 01694 // Combine with following cluster. 01695 // 01696 01697 // 01698 // Set the next cluster to the value contained in the 01699 // cluster we are merging into this one. 01700 // 01701 01702 StartingPte->u.List.NextEntry = NextPte->u.List.NextEntry; 01703 StartingPte->u.List.OneEntry = 0; 01704 PointerFollowingPte = StartingPte + 1; 01705 01706 if (NextPte->u.List.OneEntry) { 01707 Size = 1; 01708 01709 } else { 01710 NextPte++; 01711 Size = (ULONG_PTR) NextPte->u.List.NextEntry; 01712 } 01713 PointerFollowingPte->u.List.NextEntry = NumberOfPtes + Size; 01714 } 01715 #if 0 01716 if (MmDebug & MM_DBG_SYS_PTES) { 01717 MiDumpSystemPtes(SystemPtePoolType); 01718 } 01719 #endif //0 01720 01721 #if DBG 01722 if (MmDebug & MM_DBG_SYS_PTES) { 01723 ASSERT (MmTotalFreeSystemPtes[SystemPtePoolType] == 01724 MiCountFreeSystemPtes (SystemPtePoolType)); 01725 } 01726 #endif //DBG 01727 MiUnlockSystemSpace(OldIrql); 01728 return; 01729 } 01730 01731 // 01732 // Point to next freed cluster. 01733 // 01734 01735 PointerPte = NextPte; 01736 } 01737 } 01738 01739 VOID 01740 MiInitializeSystemPtes ( 01741 IN PMMPTE StartingPte, 01742 IN ULONG NumberOfPtes, 01743 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType 01744 ) 01745 01746 /*++ 01747 01748 Routine Description: 01749 01750 This routine initializes the system PTE pool. 01751 01752 Arguments: 01753 01754 StartingPte - Supplies the address of the first PTE to put in the pool. 01755 01756 NumberOfPtes - Supplies the number of PTEs to put in the pool. 01757 01758 SystemPtePoolType - Supplies the PTE type of the pool to initialize, one of 01759 SystemPteSpace or NonPagedPoolExpansion. 01760 01761 Return Value: 01762 01763 none. 01764 01765 Environment: 01766 01767 Kernel mode. 01768 01769 --*/ 01770 01771 { 01772 LONG i; 01773 LONG j; 01774 #ifdef _MI_SYSPTE_DEBUG_ 01775 PMMPTE_TRACKER Tracker; 01776 #endif 01777 01778 // 01779 // Set the base of the system PTE pool to this PTE. This takes into 01780 // account that systems may have additional PTE pools below the PTE_BASE. 01781 // 01782 01783 MmSystemPteBase = MI_PTE_BASE_FOR_LOWEST_KERNEL_ADDRESS; 01784 01785 MmSystemPtesStart[SystemPtePoolType] = StartingPte; 01786 MmSystemPtesEnd[SystemPtePoolType] = StartingPte + NumberOfPtes - 1; 01787 01788 // 01789 // If there are no PTEs specified, then make a valid chain by indicating 01790 // that the list is empty. 01791 // 01792 01793 if (NumberOfPtes == 0) { 01794 MmFirstFreeSystemPte[SystemPtePoolType] = ZeroKernelPte; 01795 MmFirstFreeSystemPte[SystemPtePoolType].u.List.NextEntry = 01796 MM_EMPTY_LIST; 01797 return; 01798 } 01799 01800 // 01801 // Initialize the specified system pte pool. 01802 // 01803 01804 MiFillMemoryPte (StartingPte, 01805 NumberOfPtes * sizeof (MMPTE), 01806 ZeroKernelPte.u.Long); 01807 01808 // 01809 // The page frame field points to the next cluster. As we only 01810 // have one cluster at initialization time, mark it as the last 01811 // cluster. 01812 // 01813 01814 StartingPte->u.List.NextEntry = MM_EMPTY_LIST; 01815 01816 MmFirstFreeSystemPte[SystemPtePoolType] = ZeroKernelPte; 01817 MmFirstFreeSystemPte[SystemPtePoolType].u.List.NextEntry = 01818 StartingPte - MmSystemPteBase; 01819 01820 // 01821 // If there is only one PTE in the pool, then mark it as a one entry 01822 // PTE. Otherwise, store the cluster size in the following PTE. 01823 // 01824 01825 if (NumberOfPtes == 1) { 01826 StartingPte->u.List.OneEntry = TRUE; 01827 01828 } else { 01829 StartingPte += 1; 01830 MI_WRITE_INVALID_PTE (StartingPte, ZeroKernelPte); 01831 StartingPte->u.List.NextEntry = NumberOfPtes; 01832 } 01833 01834 // 01835 // Set the total number of free PTEs for the specified type. 01836 // 01837 01838 MmTotalFreeSystemPtes[SystemPtePoolType] = NumberOfPtes; 01839 01840 ASSERT (MmTotalFreeSystemPtes[SystemPtePoolType] == 01841 MiCountFreeSystemPtes (SystemPtePoolType)); 01842 01843 if (SystemPtePoolType == SystemPteSpace) { 01844 01845 ULONG Lists[MM_SYS_PTE_TABLES_MAX] = {MM_PTE_LIST_1, MM_PTE_LIST_2, MM_PTE_LIST_4, MM_PTE_LIST_8, MM_PTE_LIST_16}; 01846 PMMPTE PointerPte; 01847 ULONG total; 01848 01849 #ifdef _MI_SYSPTE_DEBUG_ 01850 Tracker = (PMMPTE_TRACKER) MiAllocatePoolPages ( 01851 NonPagedPool, 01852 NumberOfPtes * sizeof (MMPTE_TRACKER), 01853 0); 01854 01855 if (Tracker) { 01856 RtlZeroMemory (Tracker, NumberOfPtes * sizeof (MMPTE_TRACKER)); 01857 } 01858 #endif 01859 01860 for (j = 0; j < MM_SYS_PTE_TABLES_MAX ; j++) { 01861 MmFreeSysPteListBySize [j].u.List.NextEntry = MM_EMPTY_PTE_LIST; 01862 MmLastSysPteListBySize [j] = &MmFreeSysPteListBySize [j]; 01863 } 01864 MmFlushCounter += 1; 01865 01866 #ifndef _MI_GUARD_PTE_ 01867 01868 // 01869 // Initialize the by size lists. 01870 // 01871 01872 total = MM_PTE_LIST_1 * MmSysPteIndex[0] + 01873 MM_PTE_LIST_2 * MmSysPteIndex[1] + 01874 MM_PTE_LIST_4 * MmSysPteIndex[2] + 01875 MM_PTE_LIST_8 * MmSysPteIndex[3] + 01876 MM_PTE_LIST_16 * MmSysPteIndex[4]; 01877 01878 PointerPte = MiReserveSystemPtes (total, 01879 SystemPteSpace, 01880 64*1024, 01881 0, 01882 TRUE); 01883 01884 for (i = (MM_SYS_PTE_TABLES_MAX - 1); i >= 0; i--) { 01885 do { 01886 Lists[i] -= 1; 01887 MiReleaseSystemPtes (PointerPte, 01888 MmSysPteIndex[i], 01889 SystemPteSpace); 01890 PointerPte += MmSysPteIndex[i]; 01891 } while (Lists[i] != 0 ); 01892 } 01893 #endif 01894 01895 MmFlushCounter += 1; 01896 MmFlushPte1 = NULL; 01897 01898 #ifdef _MI_SYSPTE_DEBUG_ 01899 MiPteTracker = Tracker; 01900 #endif 01901 } 01902 01903 return; 01904 } 01905 01906 VOID 01907 MiAddSystemPtes( 01908 IN PMMPTE StartingPte, 01909 IN ULONG NumberOfPtes, 01910 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType 01911 ) 01912 01913 /*++ 01914 01915 Routine Description: 01916 01917 This routine adds newly created PTEs to the specified pool. 01918 01919 Arguments: 01920 01921 StartingPte - Supplies the address of the first PTE to put in the pool. 01922 01923 NumberOfPtes - Supplies the number of PTEs to put in the pool. 01924 01925 SystemPtePoolType - Supplies the PTE type of the pool to expand, one of 01926 SystemPteSpace or NonPagedPoolExpansion. 01927 01928 Return Value: 01929 01930 None. 01931 01932 Environment: 01933 01934 Kernel mode. 01935 01936 --*/ 01937 01938 { 01939 PMMPTE EndingPte; 01940 01941 EndingPte = StartingPte + NumberOfPtes - 1; 01942 01943 #ifdef _MI_SYSPTE_DEBUG_ 01944 MiRebuildPteTracker (StartingPte, NumberOfPtes); 01945 #endif 01946 01947 if (StartingPte < MmSystemPtesStart[SystemPtePoolType]) { 01948 MmSystemPtesStart[SystemPtePoolType] = StartingPte; 01949 } 01950 01951 if (EndingPte > MmSystemPtesEnd[SystemPtePoolType]) { 01952 MmSystemPtesEnd[SystemPtePoolType] = EndingPte; 01953 } 01954 01955 #ifdef _MI_SYSPTE_DEBUG_ 01956 01957 if (SystemPtePoolType == SystemPteSpace && MiPteTracker != NULL) { 01958 01959 ULONG i; 01960 ULONG_PTR Index; 01961 PMMPTE_TRACKER Tracker; 01962 01963 Index = StartingPte - MmSystemPtesStart[SystemPteSpace]; 01964 Tracker = &MiPteTracker[Index]; 01965 01966 ASSERT (NumberOfPtes < 0x10000); 01967 Tracker->NumberOfPtes = (USHORT)NumberOfPtes; 01968 01969 for (i = 0; i < NumberOfPtes; i += 1) { 01970 Tracker->InUse = TRUE; 01971 Tracker += 1; 01972 } 01973 } 01974 01975 MiFillMemoryPte (StartingPte, NumberOfPtes * sizeof (MMPTE), MM_KERNEL_NOACCESS_PTE); 01976 #endif 01977 01978 #ifdef _MI_GUARD_PTE_ 01979 MiReleaseSystemPtes (StartingPte, NumberOfPtes - 1, SystemPtePoolType); 01980 #else 01981 MiReleaseSystemPtes (StartingPte, NumberOfPtes, SystemPtePoolType); 01982 #endif 01983 } 01984 01985 01986 ULONG 01987 MiGetSystemPteListCount ( 01988 IN ULONG ListSize 01989 ) 01990 01991 /*++ 01992 01993 Routine Description: 01994 01995 This routine returns the number of free entries of the list which 01996 covers the specified size. The size must be less than or equal to the 01997 largest list index. 01998 01999 Arguments: 02000 02001 ListSize - Supplies the number of PTEs needed. 02002 02003 Return Value: 02004 02005 Number of free entries on the list which contains ListSize PTEs. 02006 02007 Environment: 02008 02009 Kernel mode. 02010 02011 --*/ 02012 02013 { 02014 #ifdef _MI_GUARD_PTE_ 02015 UNREFERENCED_PARAMETER (ListSize); 02016 02017 return 8; 02018 #else 02019 ULONG Index; 02020 02021 ASSERT (ListSize <= MM_PTE_TABLE_LIMIT); 02022 02023 Index = MmSysPteTables [ListSize]; 02024 return MmSysPteListBySizeCount[Index]; 02025 #endif 02026 } 02027 02028 02029 LOGICAL 02030 MiGetSystemPteAvailability ( 02031 IN ULONG NumberOfPtes, 02032 IN MM_PAGE_PRIORITY Priority 02033 ) 02034 02035 /*++ 02036 02037 Routine Description: 02038 02039 This routine checks how many SystemPteSpace PTEs are available for the 02040 requested size. If plenty are available then TRUE is returned. 02041 If we are reaching a low resource situation, then the request is evaluated 02042 based on the argument priority. 02043 02044 Arguments: 02045 02046 NumberOfPtes - Supplies the number of PTEs needed. 02047 02048 Priority - Supplies the priority of the request. 02049 02050 Return Value: 02051 02052 TRUE if the caller should allocate the PTEs, FALSE if not. 02053 02054 Environment: 02055 02056 Kernel mode. 02057 02058 --*/ 02059 02060 { 02061 ULONG Index; 02062 ULONG FreePtes; 02063 ULONG FreeBinnedPtes; 02064 02065 if (Priority == HighPagePriority) { 02066 return TRUE; 02067 } 02068 02069 #ifdef _MI_GUARD_PTE_ 02070 NumberOfPtes += 1; 02071 #endif 02072 02073 FreePtes = MmTotalFreeSystemPtes[SystemPteSpace]; 02074 02075 if (NumberOfPtes <= MM_PTE_TABLE_LIMIT) { 02076 Index = MmSysPteTables [NumberOfPtes]; 02077 FreeBinnedPtes = MmSysPteListBySizeCount[Index]; 02078 02079 if (FreeBinnedPtes > MmSysPteMinimumFree[Index]) { 02080 return TRUE; 02081 } 02082 if (FreeBinnedPtes != 0) { 02083 if (Priority == NormalPagePriority) { 02084 if (FreeBinnedPtes > 1 || FreePtes > 512) { 02085 return TRUE; 02086 } 02087 return FALSE; 02088 } 02089 if (FreePtes > 2048) { 02090 return TRUE; 02091 } 02092 return FALSE; 02093 } 02094 } 02095 02096 if (Priority == NormalPagePriority) { 02097 if ((LONG)NumberOfPtes < (LONG)FreePtes - 512) { 02098 return TRUE; 02099 } 02100 return FALSE; 02101 } 02102 02103 if ((LONG)NumberOfPtes < (LONG)FreePtes - 2048) { 02104 return TRUE; 02105 } 02106 return FALSE; 02107 } 02108 02109 #if DBG 02110 02111 VOID 02112 MiDumpSystemPtes ( 02113 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType 02114 ) 02115 02116 02117 { 02118 PMMPTE PointerPte; 02119 PMMPTE PointerNextPte; 02120 ULONG_PTR ClusterSize; 02121 PMMPTE EndOfCluster; 02122 02123 PointerPte = &MmFirstFreeSystemPte[SystemPtePoolType]; 02124 if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) { 02125 return; 02126 } 02127 02128 PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry; 02129 02130 for (;;) { 02131 if (PointerPte->u.List.OneEntry) { 02132 ClusterSize = 1; 02133 } else { 02134 PointerNextPte = PointerPte + 1; 02135 ClusterSize = (ULONG_PTR) PointerNextPte->u.List.NextEntry; 02136 } 02137 02138 EndOfCluster = PointerPte + (ClusterSize - 1); 02139 02140 DbgPrint("System Pte at %p for %p entries (%p)\n", 02141 PointerPte, ClusterSize, EndOfCluster); 02142 02143 if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) { 02144 break; 02145 } 02146 02147 PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry; 02148 } 02149 return; 02150 } 02151 02152 ULONG 02153 MiCountFreeSystemPtes ( 02154 IN MMSYSTEM_PTE_POOL_TYPE SystemPtePoolType 02155 ) 02156 02157 { 02158 PMMPTE PointerPte; 02159 PMMPTE PointerNextPte; 02160 ULONG_PTR ClusterSize; 02161 ULONG_PTR FreeCount; 02162 02163 PointerPte = &MmFirstFreeSystemPte[SystemPtePoolType]; 02164 if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) { 02165 return 0; 02166 } 02167 02168 FreeCount = 0; 02169 02170 PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry; 02171 02172 for (;;) { 02173 if (PointerPte->u.List.OneEntry) { 02174 ClusterSize = 1; 02175 02176 } else { 02177 PointerNextPte = PointerPte + 1; 02178 ClusterSize = (ULONG_PTR) PointerNextPte->u.List.NextEntry; 02179 } 02180 02181 FreeCount += ClusterSize; 02182 if (PointerPte->u.List.NextEntry == MM_EMPTY_PTE_LIST) { 02183 break; 02184 } 02185 02186 PointerPte = MmSystemPteBase + PointerPte->u.List.NextEntry; 02187 } 02188 02189 return (ULONG)FreeCount; 02190 } 02191 02192 #endif //DBG 02193

Generated on Sat May 15 19:41:57 2004 for test by doxygen 1.3.7