Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpool.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: BSD - See COPYING.ARM in the top level directory 00004 * FILE: ntoskrnl/mm/ARM3/pool.c 00005 * PURPOSE: ARM Memory Manager Pool Allocator 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 */ 00008 00009 /* INCLUDES *******************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 #define MODULE_INVOLVED_IN_ARM3 00016 #include "../ARM3/miarm.h" 00017 00018 /* GLOBALS ********************************************************************/ 00019 00020 LIST_ENTRY MmNonPagedPoolFreeListHead[MI_MAX_FREE_PAGE_LISTS]; 00021 PFN_COUNT MmNumberOfFreeNonPagedPool, MiExpansionPoolPagesInitialCharge; 00022 PVOID MmNonPagedPoolEnd0; 00023 PFN_NUMBER MiStartOfInitialPoolFrame, MiEndOfInitialPoolFrame; 00024 KGUARDED_MUTEX MmPagedPoolMutex; 00025 MM_PAGED_POOL_INFO MmPagedPoolInfo; 00026 SIZE_T MmAllocatedNonPagedPool; 00027 ULONG MmSpecialPoolTag; 00028 ULONG MmConsumedPoolPercentage; 00029 BOOLEAN MmProtectFreedNonPagedPool; 00030 SLIST_HEADER MiNonPagedPoolSListHead; 00031 ULONG MiNonPagedPoolSListMaximum = 4; 00032 SLIST_HEADER MiPagedPoolSListHead; 00033 ULONG MiPagedPoolSListMaximum = 8; 00034 00035 /* PRIVATE FUNCTIONS **********************************************************/ 00036 00037 VOID 00038 NTAPI 00039 MiProtectFreeNonPagedPool(IN PVOID VirtualAddress, 00040 IN ULONG PageCount) 00041 { 00042 PMMPTE PointerPte, LastPte; 00043 MMPTE TempPte; 00044 00045 /* If pool is physical, can't protect PTEs */ 00046 if (MI_IS_PHYSICAL_ADDRESS(VirtualAddress)) return; 00047 00048 /* Get PTE pointers and loop */ 00049 PointerPte = MiAddressToPte(VirtualAddress); 00050 LastPte = PointerPte + PageCount; 00051 do 00052 { 00053 /* Capture the PTE for safety */ 00054 TempPte = *PointerPte; 00055 00056 /* Mark it as an invalid PTE, set proto bit to recognize it as pool */ 00057 TempPte.u.Hard.Valid = 0; 00058 TempPte.u.Soft.Prototype = 1; 00059 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 00060 } while (++PointerPte < LastPte); 00061 00062 /* Flush the TLB */ 00063 KeFlushEntireTb(TRUE, TRUE); 00064 } 00065 00066 BOOLEAN 00067 NTAPI 00068 MiUnProtectFreeNonPagedPool(IN PVOID VirtualAddress, 00069 IN ULONG PageCount) 00070 { 00071 PMMPTE PointerPte; 00072 MMPTE TempPte; 00073 PFN_NUMBER UnprotectedPages = 0; 00074 00075 /* If pool is physical, can't protect PTEs */ 00076 if (MI_IS_PHYSICAL_ADDRESS(VirtualAddress)) return FALSE; 00077 00078 /* Get, and capture the PTE */ 00079 PointerPte = MiAddressToPte(VirtualAddress); 00080 TempPte = *PointerPte; 00081 00082 /* Loop protected PTEs */ 00083 while ((TempPte.u.Hard.Valid == 0) && (TempPte.u.Soft.Prototype == 1)) 00084 { 00085 /* Unprotect the PTE */ 00086 TempPte.u.Hard.Valid = 1; 00087 TempPte.u.Soft.Prototype = 0; 00088 MI_WRITE_VALID_PTE(PointerPte, TempPte); 00089 00090 /* One more page */ 00091 if (++UnprotectedPages == PageCount) break; 00092 00093 /* Capture next PTE */ 00094 TempPte = *(++PointerPte); 00095 } 00096 00097 /* Return if any pages were unprotected */ 00098 return UnprotectedPages ? TRUE : FALSE; 00099 } 00100 00101 VOID 00102 FORCEINLINE 00103 MiProtectedPoolUnProtectLinks(IN PLIST_ENTRY Links, 00104 OUT PVOID* PoolFlink, 00105 OUT PVOID* PoolBlink) 00106 { 00107 BOOLEAN Safe; 00108 PVOID PoolVa; 00109 00110 /* Initialize variables */ 00111 *PoolFlink = *PoolBlink = NULL; 00112 00113 /* Check if the list has entries */ 00114 if (IsListEmpty(Links) == FALSE) 00115 { 00116 /* We are going to need to forward link to do an insert */ 00117 PoolVa = Links->Flink; 00118 00119 /* So make it safe to access */ 00120 Safe = MiUnProtectFreeNonPagedPool(PoolVa, 1); 00121 if (Safe) PoolFlink = PoolVa; 00122 } 00123 00124 /* Are we going to need a backward link too? */ 00125 if (Links != Links->Blink) 00126 { 00127 /* Get the head's backward link for the insert */ 00128 PoolVa = Links->Blink; 00129 00130 /* Make it safe to access */ 00131 Safe = MiUnProtectFreeNonPagedPool(PoolVa, 1); 00132 if (Safe) PoolBlink = PoolVa; 00133 } 00134 } 00135 00136 VOID 00137 FORCEINLINE 00138 MiProtectedPoolProtectLinks(IN PVOID PoolFlink, 00139 IN PVOID PoolBlink) 00140 { 00141 /* Reprotect the pages, if they got unprotected earlier */ 00142 if (PoolFlink) MiProtectFreeNonPagedPool(PoolFlink, 1); 00143 if (PoolBlink) MiProtectFreeNonPagedPool(PoolBlink, 1); 00144 } 00145 00146 VOID 00147 NTAPI 00148 MiProtectedPoolInsertList(IN PLIST_ENTRY ListHead, 00149 IN PLIST_ENTRY Entry, 00150 IN BOOLEAN Critical) 00151 { 00152 PVOID PoolFlink, PoolBlink; 00153 00154 /* Make the list accessible */ 00155 MiProtectedPoolUnProtectLinks(ListHead, &PoolFlink, &PoolBlink); 00156 00157 /* Now insert in the right position */ 00158 Critical ? InsertHeadList(ListHead, Entry) : InsertTailList(ListHead, Entry); 00159 00160 /* And reprotect the pages containing the free links */ 00161 MiProtectedPoolProtectLinks(PoolFlink, PoolBlink); 00162 } 00163 00164 VOID 00165 NTAPI 00166 MiProtectedPoolRemoveEntryList(IN PLIST_ENTRY Entry) 00167 { 00168 PVOID PoolFlink, PoolBlink; 00169 00170 /* Make the list accessible */ 00171 MiProtectedPoolUnProtectLinks(Entry, &PoolFlink, &PoolBlink); 00172 00173 /* Now remove */ 00174 RemoveEntryList(Entry); 00175 00176 /* And reprotect the pages containing the free links */ 00177 if (PoolFlink) MiProtectFreeNonPagedPool(PoolFlink, 1); 00178 if (PoolBlink) MiProtectFreeNonPagedPool(PoolBlink, 1); 00179 } 00180 00181 VOID 00182 NTAPI 00183 INIT_FUNCTION 00184 MiInitializeNonPagedPoolThresholds(VOID) 00185 { 00186 PFN_NUMBER Size = MmMaximumNonPagedPoolInPages; 00187 00188 /* Default low threshold of 8MB or one third of nonpaged pool */ 00189 MiLowNonPagedPoolThreshold = (8 * _1MB) >> PAGE_SHIFT; 00190 MiLowNonPagedPoolThreshold = min(MiLowNonPagedPoolThreshold, Size / 3); 00191 00192 /* Default high threshold of 20MB or 50% */ 00193 MiHighNonPagedPoolThreshold = (20 * _1MB) >> PAGE_SHIFT; 00194 MiHighNonPagedPoolThreshold = min(MiHighNonPagedPoolThreshold, Size / 2); 00195 ASSERT(MiLowNonPagedPoolThreshold < MiHighNonPagedPoolThreshold); 00196 } 00197 00198 VOID 00199 NTAPI 00200 INIT_FUNCTION 00201 MiInitializePoolEvents(VOID) 00202 { 00203 KIRQL OldIrql; 00204 PFN_NUMBER FreePoolInPages; 00205 00206 /* Lock paged pool */ 00207 KeAcquireGuardedMutex(&MmPagedPoolMutex); 00208 00209 /* Total size of the paged pool minus the allocated size, is free */ 00210 FreePoolInPages = MmSizeOfPagedPoolInPages - MmPagedPoolInfo.AllocatedPagedPool; 00211 00212 /* Check the initial state high state */ 00213 if (FreePoolInPages >= MiHighPagedPoolThreshold) 00214 { 00215 /* We have plenty of pool */ 00216 KeSetEvent(MiHighPagedPoolEvent, 0, FALSE); 00217 } 00218 else 00219 { 00220 /* We don't */ 00221 KeClearEvent(MiHighPagedPoolEvent); 00222 } 00223 00224 /* Check the initial low state */ 00225 if (FreePoolInPages <= MiLowPagedPoolThreshold) 00226 { 00227 /* We're very low in free pool memory */ 00228 KeSetEvent(MiLowPagedPoolEvent, 0, FALSE); 00229 } 00230 else 00231 { 00232 /* We're not */ 00233 KeClearEvent(MiLowPagedPoolEvent); 00234 } 00235 00236 /* Release the paged pool lock */ 00237 KeReleaseGuardedMutex(&MmPagedPoolMutex); 00238 00239 /* Now it's time for the nonpaged pool lock */ 00240 OldIrql = KeAcquireQueuedSpinLock(LockQueueMmNonPagedPoolLock); 00241 00242 /* Free pages are the maximum minus what's been allocated */ 00243 FreePoolInPages = MmMaximumNonPagedPoolInPages - MmAllocatedNonPagedPool; 00244 00245 /* Check if we have plenty */ 00246 if (FreePoolInPages >= MiHighNonPagedPoolThreshold) 00247 { 00248 /* We do, set the event */ 00249 KeSetEvent(MiHighNonPagedPoolEvent, 0, FALSE); 00250 } 00251 else 00252 { 00253 /* We don't, clear the event */ 00254 KeClearEvent(MiHighNonPagedPoolEvent); 00255 } 00256 00257 /* Check if we have very little */ 00258 if (FreePoolInPages <= MiLowNonPagedPoolThreshold) 00259 { 00260 /* We do, set the event */ 00261 KeSetEvent(MiLowNonPagedPoolEvent, 0, FALSE); 00262 } 00263 else 00264 { 00265 /* We don't, clear it */ 00266 KeClearEvent(MiLowNonPagedPoolEvent); 00267 } 00268 00269 /* We're done, release the nonpaged pool lock */ 00270 KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql); 00271 } 00272 00273 VOID 00274 NTAPI 00275 INIT_FUNCTION 00276 MiInitializeNonPagedPool(VOID) 00277 { 00278 ULONG i; 00279 PFN_COUNT PoolPages; 00280 PMMFREE_POOL_ENTRY FreeEntry, FirstEntry; 00281 PMMPTE PointerPte; 00282 PAGED_CODE(); 00283 00284 // 00285 // Initialize the pool S-LISTs as well as their maximum count. In general, 00286 // we'll allow 8 times the default on a 2GB system, and two times the default 00287 // on a 1GB system. 00288 // 00289 InitializeSListHead(&MiPagedPoolSListHead); 00290 InitializeSListHead(&MiNonPagedPoolSListHead); 00291 if (MmNumberOfPhysicalPages >= ((2 * _1GB) /PAGE_SIZE)) 00292 { 00293 MiNonPagedPoolSListMaximum *= 8; 00294 MiPagedPoolSListMaximum *= 8; 00295 } 00296 else if (MmNumberOfPhysicalPages >= (_1GB /PAGE_SIZE)) 00297 { 00298 MiNonPagedPoolSListMaximum *= 2; 00299 MiPagedPoolSListMaximum *= 2; 00300 } 00301 00302 // 00303 // However if debugging options for the pool are enabled, turn off the S-LIST 00304 // to reduce the risk of messing things up even more 00305 // 00306 if (MmProtectFreedNonPagedPool) 00307 { 00308 MiNonPagedPoolSListMaximum = 0; 00309 MiPagedPoolSListMaximum = 0; 00310 } 00311 00312 // 00313 // We keep 4 lists of free pages (4 lists help avoid contention) 00314 // 00315 for (i = 0; i < MI_MAX_FREE_PAGE_LISTS; i++) 00316 { 00317 // 00318 // Initialize each of them 00319 // 00320 InitializeListHead(&MmNonPagedPoolFreeListHead[i]); 00321 } 00322 00323 // 00324 // Calculate how many pages the initial nonpaged pool has 00325 // 00326 PoolPages = (PFN_COUNT)BYTES_TO_PAGES(MmSizeOfNonPagedPoolInBytes); 00327 MmNumberOfFreeNonPagedPool = PoolPages; 00328 00329 // 00330 // Initialize the first free entry 00331 // 00332 FreeEntry = MmNonPagedPoolStart; 00333 FirstEntry = FreeEntry; 00334 FreeEntry->Size = PoolPages; 00335 FreeEntry->Signature = MM_FREE_POOL_SIGNATURE; 00336 FreeEntry->Owner = FirstEntry; 00337 00338 // 00339 // Insert it into the last list 00340 // 00341 InsertHeadList(&MmNonPagedPoolFreeListHead[MI_MAX_FREE_PAGE_LISTS - 1], 00342 &FreeEntry->List); 00343 00344 // 00345 // Now create free entries for every single other page 00346 // 00347 while (PoolPages-- > 1) 00348 { 00349 // 00350 // Link them all back to the original entry 00351 // 00352 FreeEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)FreeEntry + PAGE_SIZE); 00353 FreeEntry->Owner = FirstEntry; 00354 FreeEntry->Signature = MM_FREE_POOL_SIGNATURE; 00355 } 00356 00357 // 00358 // Validate and remember first allocated pool page 00359 // 00360 PointerPte = MiAddressToPte(MmNonPagedPoolStart); 00361 ASSERT(PointerPte->u.Hard.Valid == 1); 00362 MiStartOfInitialPoolFrame = PFN_FROM_PTE(PointerPte); 00363 00364 // 00365 // Keep track of where initial nonpaged pool ends 00366 // 00367 MmNonPagedPoolEnd0 = (PVOID)((ULONG_PTR)MmNonPagedPoolStart + 00368 MmSizeOfNonPagedPoolInBytes); 00369 00370 // 00371 // Validate and remember last allocated pool page 00372 // 00373 PointerPte = MiAddressToPte((PVOID)((ULONG_PTR)MmNonPagedPoolEnd0 - 1)); 00374 ASSERT(PointerPte->u.Hard.Valid == 1); 00375 MiEndOfInitialPoolFrame = PFN_FROM_PTE(PointerPte); 00376 00377 // 00378 // Validate the first nonpaged pool expansion page (which is a guard page) 00379 // 00380 PointerPte = MiAddressToPte(MmNonPagedPoolExpansionStart); 00381 ASSERT(PointerPte->u.Hard.Valid == 0); 00382 00383 // 00384 // Calculate the size of the expansion region alone 00385 // 00386 MiExpansionPoolPagesInitialCharge = (PFN_COUNT) 00387 BYTES_TO_PAGES(MmMaximumNonPagedPoolInBytes - MmSizeOfNonPagedPoolInBytes); 00388 00389 // 00390 // Remove 2 pages, since there's a guard page on top and on the bottom 00391 // 00392 MiExpansionPoolPagesInitialCharge -= 2; 00393 00394 // 00395 // Now initialize the nonpaged pool expansion PTE space. Remember there's a 00396 // guard page on top so make sure to skip it. The bottom guard page will be 00397 // guaranteed by the fact our size is off by one. 00398 // 00399 MiInitializeSystemPtes(PointerPte + 1, 00400 MiExpansionPoolPagesInitialCharge, 00401 NonPagedPoolExpansion); 00402 } 00403 00404 POOL_TYPE 00405 NTAPI 00406 MmDeterminePoolType(IN PVOID PoolAddress) 00407 { 00408 // 00409 // Use a simple bounds check 00410 // 00411 return (PoolAddress >= MmPagedPoolStart) && (PoolAddress <= MmPagedPoolEnd) ? 00412 PagedPool : NonPagedPool; 00413 } 00414 00415 PVOID 00416 NTAPI 00417 MiAllocatePoolPages(IN POOL_TYPE PoolType, 00418 IN SIZE_T SizeInBytes) 00419 { 00420 PFN_NUMBER PageFrameNumber; 00421 PFN_COUNT SizeInPages, PageTableCount; 00422 ULONG i; 00423 KIRQL OldIrql; 00424 PLIST_ENTRY NextEntry, NextHead, LastHead; 00425 PMMPTE PointerPte, StartPte; 00426 PMMPDE PointerPde; 00427 ULONG EndAllocation; 00428 MMPTE TempPte; 00429 MMPDE TempPde; 00430 PMMPFN Pfn1; 00431 PVOID BaseVa, BaseVaStart; 00432 PMMFREE_POOL_ENTRY FreeEntry; 00433 PKSPIN_LOCK_QUEUE LockQueue; 00434 00435 // 00436 // Figure out how big the allocation is in pages 00437 // 00438 SizeInPages = (PFN_COUNT)BYTES_TO_PAGES(SizeInBytes); 00439 00440 // 00441 // Check for overflow 00442 // 00443 if (SizeInPages == 0) 00444 { 00445 // 00446 // Fail 00447 // 00448 return NULL; 00449 } 00450 00451 // 00452 // Handle paged pool 00453 // 00454 if ((PoolType & BASE_POOL_TYPE_MASK) == PagedPool) 00455 { 00456 // 00457 // If only one page is being requested, try to grab it from the S-LIST 00458 // 00459 if ((SizeInPages == 1) && (ExQueryDepthSList(&MiPagedPoolSListHead))) 00460 { 00461 BaseVa = InterlockedPopEntrySList(&MiPagedPoolSListHead); 00462 if (BaseVa) return BaseVa; 00463 } 00464 00465 // 00466 // Lock the paged pool mutex 00467 // 00468 KeAcquireGuardedMutex(&MmPagedPoolMutex); 00469 00470 // 00471 // Find some empty allocation space 00472 // 00473 i = RtlFindClearBitsAndSet(MmPagedPoolInfo.PagedPoolAllocationMap, 00474 SizeInPages, 00475 MmPagedPoolInfo.PagedPoolHint); 00476 if (i == 0xFFFFFFFF) 00477 { 00478 // 00479 // Get the page bit count 00480 // 00481 i = ((SizeInPages - 1) / PTE_COUNT) + 1; 00482 DPRINT1("Paged pool expansion: %d %x\n", i, SizeInPages); 00483 00484 // 00485 // Check if there is enougn paged pool expansion space left 00486 // 00487 if (MmPagedPoolInfo.NextPdeForPagedPoolExpansion > 00488 (PMMPDE)MiAddressToPte(MmPagedPoolInfo.LastPteForPagedPool)) 00489 { 00490 // 00491 // Out of memory! 00492 // 00493 DPRINT1("OUT OF PAGED POOL!!!\n"); 00494 KeReleaseGuardedMutex(&MmPagedPoolMutex); 00495 return NULL; 00496 } 00497 00498 // 00499 // Check if we'll have to expand past the last PTE we have available 00500 // 00501 if (((i - 1) + MmPagedPoolInfo.NextPdeForPagedPoolExpansion) > 00502 (PMMPDE)MiAddressToPte(MmPagedPoolInfo.LastPteForPagedPool)) 00503 { 00504 // 00505 // We can only support this much then 00506 // 00507 PointerPde = MiAddressToPte(MmPagedPoolInfo.LastPteForPagedPool); 00508 PageTableCount = (PFN_COUNT)(PointerPde + 1 - 00509 MmPagedPoolInfo.NextPdeForPagedPoolExpansion); 00510 ASSERT(PageTableCount < i); 00511 i = PageTableCount; 00512 } 00513 else 00514 { 00515 // 00516 // Otherwise, there is plenty of space left for this expansion 00517 // 00518 PageTableCount = i; 00519 } 00520 00521 // 00522 // Get the template PDE we'll use to expand 00523 // 00524 TempPde = ValidKernelPde; 00525 00526 // 00527 // Get the first PTE in expansion space 00528 // 00529 PointerPde = MmPagedPoolInfo.NextPdeForPagedPoolExpansion; 00530 BaseVa = MiPdeToPte(PointerPde); 00531 BaseVaStart = BaseVa; 00532 00533 // 00534 // Lock the PFN database and loop pages 00535 // 00536 OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); 00537 do 00538 { 00539 // 00540 // It should not already be valid 00541 // 00542 ASSERT(PointerPde->u.Hard.Valid == 0); 00543 00544 /* Request a page */ 00545 MI_SET_USAGE(MI_USAGE_PAGED_POOL); 00546 MI_SET_PROCESS2("Kernel"); 00547 PageFrameNumber = MiRemoveAnyPage(MI_GET_NEXT_COLOR()); 00548 TempPde.u.Hard.PageFrameNumber = PageFrameNumber; 00549 #if (_MI_PAGING_LEVELS >= 3) 00550 /* On PAE/x64 systems, there's no double-buffering */ 00551 ASSERT(FALSE); 00552 #else 00553 // 00554 // Save it into our double-buffered system page directory 00555 // 00556 MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)] = TempPde; 00557 00558 /* Initialize the PFN */ 00559 MiInitializePfnForOtherProcess(PageFrameNumber, 00560 (PMMPTE)PointerPde, 00561 MmSystemPageDirectory[(PointerPde - MiAddressToPde(NULL)) / PDE_COUNT]); 00562 00563 /* Write the actual PDE now */ 00564 // MI_WRITE_VALID_PDE(PointerPde, TempPde); 00565 #endif 00566 // 00567 // Move on to the next expansion address 00568 // 00569 PointerPde++; 00570 BaseVa = (PVOID)((ULONG_PTR)BaseVa + PAGE_SIZE); 00571 i--; 00572 } while (i > 0); 00573 00574 // 00575 // Release the PFN database lock 00576 // 00577 KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); 00578 00579 // 00580 // These pages are now available, clear their availablity bits 00581 // 00582 EndAllocation = (ULONG)(MmPagedPoolInfo.NextPdeForPagedPoolExpansion - 00583 (PMMPDE)MiAddressToPte(MmPagedPoolInfo.FirstPteForPagedPool)) * 00584 PTE_COUNT; 00585 RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, 00586 EndAllocation, 00587 PageTableCount * PTE_COUNT); 00588 00589 // 00590 // Update the next expansion location 00591 // 00592 MmPagedPoolInfo.NextPdeForPagedPoolExpansion += PageTableCount; 00593 00594 // 00595 // Zero out the newly available memory 00596 // 00597 RtlZeroMemory(BaseVaStart, PageTableCount * PAGE_SIZE); 00598 00599 // 00600 // Now try consuming the pages again 00601 // 00602 i = RtlFindClearBitsAndSet(MmPagedPoolInfo.PagedPoolAllocationMap, 00603 SizeInPages, 00604 0); 00605 if (i == 0xFFFFFFFF) 00606 { 00607 // 00608 // Out of memory! 00609 // 00610 DPRINT1("OUT OF PAGED POOL!!!\n"); 00611 KeReleaseGuardedMutex(&MmPagedPoolMutex); 00612 return NULL; 00613 } 00614 } 00615 00616 // 00617 // Update the pool hint if the request was just one page 00618 // 00619 if (SizeInPages == 1) MmPagedPoolInfo.PagedPoolHint = i + 1; 00620 00621 // 00622 // Update the end bitmap so we know the bounds of this allocation when 00623 // the time comes to free it 00624 // 00625 EndAllocation = i + SizeInPages - 1; 00626 RtlSetBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, EndAllocation); 00627 00628 // 00629 // Now we can release the lock (it mainly protects the bitmap) 00630 // 00631 KeReleaseGuardedMutex(&MmPagedPoolMutex); 00632 00633 // 00634 // Now figure out where this allocation starts 00635 // 00636 BaseVa = (PVOID)((ULONG_PTR)MmPagedPoolStart + (i << PAGE_SHIFT)); 00637 00638 // 00639 // Flush the TLB 00640 // 00641 KeFlushEntireTb(TRUE, TRUE); 00642 00643 /* Setup a demand-zero writable PTE */ 00644 MI_MAKE_SOFTWARE_PTE(&TempPte, MM_READWRITE); 00645 00646 // 00647 // Find the first and last PTE, then loop them all 00648 // 00649 PointerPte = MiAddressToPte(BaseVa); 00650 StartPte = PointerPte + SizeInPages; 00651 do 00652 { 00653 // 00654 // Write the demand zero PTE and keep going 00655 // 00656 MI_WRITE_INVALID_PTE(PointerPte, TempPte); 00657 } while (++PointerPte < StartPte); 00658 00659 // 00660 // Return the allocation address to the caller 00661 // 00662 return BaseVa; 00663 } 00664 00665 // 00666 // If only one page is being requested, try to grab it from the S-LIST 00667 // 00668 if ((SizeInPages == 1) && (ExQueryDepthSList(&MiNonPagedPoolSListHead))) 00669 { 00670 BaseVa = InterlockedPopEntrySList(&MiNonPagedPoolSListHead); 00671 if (BaseVa) return BaseVa; 00672 } 00673 00674 // 00675 // Allocations of less than 4 pages go into their individual buckets 00676 // 00677 i = SizeInPages - 1; 00678 if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1; 00679 00680 // 00681 // Loop through all the free page lists based on the page index 00682 // 00683 NextHead = &MmNonPagedPoolFreeListHead[i]; 00684 LastHead = &MmNonPagedPoolFreeListHead[MI_MAX_FREE_PAGE_LISTS]; 00685 00686 // 00687 // Acquire the nonpaged pool lock 00688 // 00689 OldIrql = KeAcquireQueuedSpinLock(LockQueueMmNonPagedPoolLock); 00690 do 00691 { 00692 // 00693 // Now loop through all the free page entries in this given list 00694 // 00695 NextEntry = NextHead->Flink; 00696 while (NextEntry != NextHead) 00697 { 00698 /* Is freed non paged pool enabled */ 00699 if (MmProtectFreedNonPagedPool) 00700 { 00701 /* We need to be able to touch this page, unprotect it */ 00702 MiUnProtectFreeNonPagedPool(NextEntry, 0); 00703 } 00704 00705 // 00706 // Grab the entry and see if it can handle our allocation 00707 // 00708 FreeEntry = CONTAINING_RECORD(NextEntry, MMFREE_POOL_ENTRY, List); 00709 ASSERT(FreeEntry->Signature == MM_FREE_POOL_SIGNATURE); 00710 if (FreeEntry->Size >= SizeInPages) 00711 { 00712 // 00713 // It does, so consume the pages from here 00714 // 00715 FreeEntry->Size -= SizeInPages; 00716 00717 // 00718 // The allocation will begin in this free page area 00719 // 00720 BaseVa = (PVOID)((ULONG_PTR)FreeEntry + 00721 (FreeEntry->Size << PAGE_SHIFT)); 00722 00723 /* Remove the item from the list, depending if pool is protected */ 00724 MmProtectFreedNonPagedPool ? 00725 MiProtectedPoolRemoveEntryList(&FreeEntry->List) : 00726 RemoveEntryList(&FreeEntry->List); 00727 00728 // 00729 // However, check if its' still got space left 00730 // 00731 if (FreeEntry->Size != 0) 00732 { 00733 /* Check which list to insert this entry into */ 00734 i = FreeEntry->Size - 1; 00735 if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1; 00736 00737 /* Insert the entry into the free list head, check for prot. pool */ 00738 MmProtectFreedNonPagedPool ? 00739 MiProtectedPoolInsertList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List, TRUE) : 00740 InsertTailList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List); 00741 00742 /* Is freed non paged pool protected? */ 00743 if (MmProtectFreedNonPagedPool) 00744 { 00745 /* Protect the freed pool! */ 00746 MiProtectFreeNonPagedPool(FreeEntry, FreeEntry->Size); 00747 } 00748 } 00749 00750 // 00751 // Grab the PTE for this allocation 00752 // 00753 PointerPte = MiAddressToPte(BaseVa); 00754 ASSERT(PointerPte->u.Hard.Valid == 1); 00755 00756 // 00757 // Grab the PFN NextEntry and index 00758 // 00759 Pfn1 = MiGetPfnEntry(PFN_FROM_PTE(PointerPte)); 00760 00761 // 00762 // Now mark it as the beginning of an allocation 00763 // 00764 ASSERT(Pfn1->u3.e1.StartOfAllocation == 0); 00765 Pfn1->u3.e1.StartOfAllocation = 1; 00766 00767 /* Mark it as special pool if needed */ 00768 ASSERT(Pfn1->u4.VerifierAllocation == 0); 00769 if (PoolType & 64) Pfn1->u4.VerifierAllocation = 1; 00770 00771 // 00772 // Check if the allocation is larger than one page 00773 // 00774 if (SizeInPages != 1) 00775 { 00776 // 00777 // Navigate to the last PFN entry and PTE 00778 // 00779 PointerPte += SizeInPages - 1; 00780 ASSERT(PointerPte->u.Hard.Valid == 1); 00781 Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber); 00782 } 00783 00784 // 00785 // Mark this PFN as the last (might be the same as the first) 00786 // 00787 ASSERT(Pfn1->u3.e1.EndOfAllocation == 0); 00788 Pfn1->u3.e1.EndOfAllocation = 1; 00789 00790 // 00791 // Release the nonpaged pool lock, and return the allocation 00792 // 00793 KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql); 00794 return BaseVa; 00795 } 00796 00797 // 00798 // Try the next free page entry 00799 // 00800 NextEntry = FreeEntry->List.Flink; 00801 00802 /* Is freed non paged pool protected? */ 00803 if (MmProtectFreedNonPagedPool) 00804 { 00805 /* Protect the freed pool! */ 00806 MiProtectFreeNonPagedPool(FreeEntry, FreeEntry->Size); 00807 } 00808 } 00809 } while (++NextHead < LastHead); 00810 00811 // 00812 // If we got here, we're out of space. 00813 // Start by releasing the lock 00814 // 00815 KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql); 00816 00817 // 00818 // Allocate some system PTEs 00819 // 00820 StartPte = MiReserveSystemPtes(SizeInPages, NonPagedPoolExpansion); 00821 PointerPte = StartPte; 00822 if (StartPte == NULL) 00823 { 00824 // 00825 // Ran out of memory 00826 // 00827 DPRINT1("Out of NP Expansion Pool\n"); 00828 return NULL; 00829 } 00830 00831 // 00832 // Acquire the pool lock now 00833 // 00834 OldIrql = KeAcquireQueuedSpinLock(LockQueueMmNonPagedPoolLock); 00835 00836 // 00837 // Lock the PFN database too 00838 // 00839 LockQueue = &KeGetCurrentPrcb()->LockQueue[LockQueuePfnLock]; 00840 KeAcquireQueuedSpinLockAtDpcLevel(LockQueue); 00841 00842 // 00843 // Loop the pages 00844 // 00845 TempPte = ValidKernelPte; 00846 do 00847 { 00848 /* Allocate a page */ 00849 MI_SET_USAGE(MI_USAGE_PAGED_POOL); 00850 MI_SET_PROCESS2("Kernel"); 00851 PageFrameNumber = MiRemoveAnyPage(MI_GET_NEXT_COLOR()); 00852 00853 /* Get the PFN entry for it and fill it out */ 00854 Pfn1 = MiGetPfnEntry(PageFrameNumber); 00855 Pfn1->u3.e2.ReferenceCount = 1; 00856 Pfn1->u2.ShareCount = 1; 00857 Pfn1->PteAddress = PointerPte; 00858 Pfn1->u3.e1.PageLocation = ActiveAndValid; 00859 Pfn1->u4.VerifierAllocation = 0; 00860 00861 /* Write the PTE for it */ 00862 TempPte.u.Hard.PageFrameNumber = PageFrameNumber; 00863 MI_WRITE_VALID_PTE(PointerPte++, TempPte); 00864 } while (--SizeInPages > 0); 00865 00866 // 00867 // This is the last page 00868 // 00869 Pfn1->u3.e1.EndOfAllocation = 1; 00870 00871 // 00872 // Get the first page and mark it as such 00873 // 00874 Pfn1 = MiGetPfnEntry(StartPte->u.Hard.PageFrameNumber); 00875 Pfn1->u3.e1.StartOfAllocation = 1; 00876 00877 /* Mark it as a verifier allocation if needed */ 00878 ASSERT(Pfn1->u4.VerifierAllocation == 0); 00879 if (PoolType & 64) Pfn1->u4.VerifierAllocation = 1; 00880 00881 // 00882 // Release the PFN and nonpaged pool lock 00883 // 00884 KeReleaseQueuedSpinLockFromDpcLevel(LockQueue); 00885 KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql); 00886 00887 // 00888 // Return the address 00889 // 00890 return MiPteToAddress(StartPte); 00891 } 00892 00893 ULONG 00894 NTAPI 00895 MiFreePoolPages(IN PVOID StartingVa) 00896 { 00897 PMMPTE PointerPte, StartPte; 00898 PMMPFN Pfn1, StartPfn; 00899 PFN_COUNT FreePages, NumberOfPages; 00900 KIRQL OldIrql; 00901 PMMFREE_POOL_ENTRY FreeEntry, NextEntry, LastEntry; 00902 ULONG i, End; 00903 ULONG_PTR Offset; 00904 00905 // 00906 // Handle paged pool 00907 // 00908 if ((StartingVa >= MmPagedPoolStart) && (StartingVa <= MmPagedPoolEnd)) 00909 { 00910 // 00911 // Calculate the offset from the beginning of paged pool, and convert it 00912 // into pages 00913 // 00914 Offset = (ULONG_PTR)StartingVa - (ULONG_PTR)MmPagedPoolStart; 00915 i = (ULONG)(Offset >> PAGE_SHIFT); 00916 End = i; 00917 00918 // 00919 // Now use the end bitmap to scan until we find a set bit, meaning that 00920 // this allocation finishes here 00921 // 00922 while (!RtlTestBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, End)) End++; 00923 00924 // 00925 // Now calculate the total number of pages this allocation spans. If it's 00926 // only one page, add it to the S-LIST instead of freeing it 00927 // 00928 NumberOfPages = End - i + 1; 00929 if ((NumberOfPages == 1) && 00930 (ExQueryDepthSList(&MiPagedPoolSListHead) < MiPagedPoolSListMaximum)) 00931 { 00932 InterlockedPushEntrySList(&MiPagedPoolSListHead, StartingVa); 00933 return 1; 00934 } 00935 00936 /* Delete the actual pages */ 00937 PointerPte = MmPagedPoolInfo.FirstPteForPagedPool + i; 00938 FreePages = MiDeleteSystemPageableVm(PointerPte, NumberOfPages, 0, NULL); 00939 ASSERT(FreePages == NumberOfPages); 00940 00941 // 00942 // Acquire the paged pool lock 00943 // 00944 KeAcquireGuardedMutex(&MmPagedPoolMutex); 00945 00946 // 00947 // Clear the allocation and free bits 00948 // 00949 RtlClearBit(MmPagedPoolInfo.EndOfPagedPoolBitmap, End); 00950 RtlClearBits(MmPagedPoolInfo.PagedPoolAllocationMap, i, NumberOfPages); 00951 00952 // 00953 // Update the hint if we need to 00954 // 00955 if (i < MmPagedPoolInfo.PagedPoolHint) MmPagedPoolInfo.PagedPoolHint = i; 00956 00957 // 00958 // Release the lock protecting the bitmaps 00959 // 00960 KeReleaseGuardedMutex(&MmPagedPoolMutex); 00961 00962 // 00963 // And finally return the number of pages freed 00964 // 00965 return NumberOfPages; 00966 } 00967 00968 // 00969 // Get the first PTE and its corresponding PFN entry. If this is also the 00970 // last PTE, meaning that this allocation was only for one page, push it into 00971 // the S-LIST instead of freeing it 00972 // 00973 StartPte = PointerPte = MiAddressToPte(StartingVa); 00974 StartPfn = Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber); 00975 if ((Pfn1->u3.e1.EndOfAllocation == 1) && 00976 (ExQueryDepthSList(&MiNonPagedPoolSListHead) < MiNonPagedPoolSListMaximum)) 00977 { 00978 InterlockedPushEntrySList(&MiNonPagedPoolSListHead, StartingVa); 00979 return 1; 00980 } 00981 00982 // 00983 // Loop until we find the last PTE 00984 // 00985 while (Pfn1->u3.e1.EndOfAllocation == 0) 00986 { 00987 // 00988 // Keep going 00989 // 00990 PointerPte++; 00991 Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber); 00992 } 00993 00994 // 00995 // Now we know how many pages we have 00996 // 00997 NumberOfPages = (PFN_COUNT)(PointerPte - StartPte + 1); 00998 00999 // 01000 // Acquire the nonpaged pool lock 01001 // 01002 OldIrql = KeAcquireQueuedSpinLock(LockQueueMmNonPagedPoolLock); 01003 01004 // 01005 // Mark the first and last PTEs as not part of an allocation anymore 01006 // 01007 StartPfn->u3.e1.StartOfAllocation = 0; 01008 Pfn1->u3.e1.EndOfAllocation = 0; 01009 01010 // 01011 // Assume we will free as many pages as the allocation was 01012 // 01013 FreePages = NumberOfPages; 01014 01015 // 01016 // Peek one page past the end of the allocation 01017 // 01018 PointerPte++; 01019 01020 // 01021 // Guard against going past initial nonpaged pool 01022 // 01023 if (MiGetPfnEntryIndex(Pfn1) == MiEndOfInitialPoolFrame) 01024 { 01025 // 01026 // This page is on the outskirts of initial nonpaged pool, so ignore it 01027 // 01028 Pfn1 = NULL; 01029 } 01030 else 01031 { 01032 /* Sanity check */ 01033 ASSERT((ULONG_PTR)StartingVa + NumberOfPages <= (ULONG_PTR)MmNonPagedPoolEnd); 01034 01035 /* Check if protected pool is enabled */ 01036 if (MmProtectFreedNonPagedPool) 01037 { 01038 /* The freed block will be merged, it must be made accessible */ 01039 MiUnProtectFreeNonPagedPool(MiPteToAddress(PointerPte), 0); 01040 } 01041 01042 // 01043 // Otherwise, our entire allocation must've fit within the initial non 01044 // paged pool, or the expansion nonpaged pool, so get the PFN entry of 01045 // the next allocation 01046 // 01047 if (PointerPte->u.Hard.Valid == 1) 01048 { 01049 // 01050 // It's either expansion or initial: get the PFN entry 01051 // 01052 Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber); 01053 } 01054 else 01055 { 01056 // 01057 // This means we've reached the guard page that protects the end of 01058 // the expansion nonpaged pool 01059 // 01060 Pfn1 = NULL; 01061 } 01062 01063 } 01064 01065 // 01066 // Check if this allocation actually exists 01067 // 01068 if ((Pfn1) && (Pfn1->u3.e1.StartOfAllocation == 0)) 01069 { 01070 // 01071 // It doesn't, so we should actually locate a free entry descriptor 01072 // 01073 FreeEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)StartingVa + 01074 (NumberOfPages << PAGE_SHIFT)); 01075 ASSERT(FreeEntry->Signature == MM_FREE_POOL_SIGNATURE); 01076 ASSERT(FreeEntry->Owner == FreeEntry); 01077 01078 /* Consume this entry's pages */ 01079 FreePages += FreeEntry->Size; 01080 01081 /* Remove the item from the list, depending if pool is protected */ 01082 MmProtectFreedNonPagedPool ? 01083 MiProtectedPoolRemoveEntryList(&FreeEntry->List) : 01084 RemoveEntryList(&FreeEntry->List); 01085 } 01086 01087 // 01088 // Now get the official free entry we'll create for the caller's allocation 01089 // 01090 FreeEntry = StartingVa; 01091 01092 // 01093 // Check if the our allocation is the very first page 01094 // 01095 if (MiGetPfnEntryIndex(StartPfn) == MiStartOfInitialPoolFrame) 01096 { 01097 // 01098 // Then we can't do anything or we'll risk underflowing 01099 // 01100 Pfn1 = NULL; 01101 } 01102 else 01103 { 01104 // 01105 // Otherwise, get the PTE for the page right before our allocation 01106 // 01107 PointerPte -= NumberOfPages + 1; 01108 01109 /* Check if protected pool is enabled */ 01110 if (MmProtectFreedNonPagedPool) 01111 { 01112 /* The freed block will be merged, it must be made accessible */ 01113 MiUnProtectFreeNonPagedPool(MiPteToAddress(PointerPte), 0); 01114 } 01115 01116 /* Check if this is valid pool, or a guard page */ 01117 if (PointerPte->u.Hard.Valid == 1) 01118 { 01119 // 01120 // It's either expansion or initial nonpaged pool, get the PFN entry 01121 // 01122 Pfn1 = MiGetPfnEntry(PointerPte->u.Hard.PageFrameNumber); 01123 } 01124 else 01125 { 01126 // 01127 // We must've reached the guard page, so don't risk touching it 01128 // 01129 Pfn1 = NULL; 01130 } 01131 } 01132 01133 // 01134 // Check if there is a valid PFN entry for the page before the allocation 01135 // and then check if this page was actually the end of an allocation. 01136 // If it wasn't, then we know for sure it's a free page 01137 // 01138 if ((Pfn1) && (Pfn1->u3.e1.EndOfAllocation == 0)) 01139 { 01140 // 01141 // Get the free entry descriptor for that given page range 01142 // 01143 FreeEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)StartingVa - PAGE_SIZE); 01144 ASSERT(FreeEntry->Signature == MM_FREE_POOL_SIGNATURE); 01145 FreeEntry = FreeEntry->Owner; 01146 01147 /* Check if protected pool is enabled */ 01148 if (MmProtectFreedNonPagedPool) 01149 { 01150 /* The freed block will be merged, it must be made accessible */ 01151 MiUnProtectFreeNonPagedPool(FreeEntry, 0); 01152 } 01153 01154 // 01155 // Check if the entry is small enough to be indexed on a free list 01156 // If it is, we'll want to re-insert it, since we're about to 01157 // collapse our pages on top of it, which will change its count 01158 // 01159 if (FreeEntry->Size < (MI_MAX_FREE_PAGE_LISTS - 1)) 01160 { 01161 /* Remove the item from the list, depending if pool is protected */ 01162 MmProtectFreedNonPagedPool ? 01163 MiProtectedPoolRemoveEntryList(&FreeEntry->List) : 01164 RemoveEntryList(&FreeEntry->List); 01165 01166 // 01167 // Update its size 01168 // 01169 FreeEntry->Size += FreePages; 01170 01171 // 01172 // And now find the new appropriate list to place it in 01173 // 01174 i = (ULONG)(FreeEntry->Size - 1); 01175 if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1; 01176 01177 /* Insert the entry into the free list head, check for prot. pool */ 01178 MmProtectFreedNonPagedPool ? 01179 MiProtectedPoolInsertList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List, TRUE) : 01180 InsertTailList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List); 01181 } 01182 else 01183 { 01184 // 01185 // Otherwise, just combine our free pages into this entry 01186 // 01187 FreeEntry->Size += FreePages; 01188 } 01189 } 01190 01191 // 01192 // Check if we were unable to do any compaction, and we'll stick with this 01193 // 01194 if (FreeEntry == StartingVa) 01195 { 01196 // 01197 // Well, now we are a free entry. At worse we just have our newly freed 01198 // pages, at best we have our pages plus whatever entry came after us 01199 // 01200 FreeEntry->Size = FreePages; 01201 01202 // 01203 // Find the appropriate list we should be on 01204 // 01205 i = FreeEntry->Size - 1; 01206 if (i >= MI_MAX_FREE_PAGE_LISTS) i = MI_MAX_FREE_PAGE_LISTS - 1; 01207 01208 /* Insert the entry into the free list head, check for prot. pool */ 01209 MmProtectFreedNonPagedPool ? 01210 MiProtectedPoolInsertList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List, TRUE) : 01211 InsertTailList(&MmNonPagedPoolFreeListHead[i], &FreeEntry->List); 01212 } 01213 01214 // 01215 // Just a sanity check 01216 // 01217 ASSERT(FreePages != 0); 01218 01219 // 01220 // Get all the pages between our allocation and its end. These will all now 01221 // become free page chunks. 01222 // 01223 NextEntry = StartingVa; 01224 LastEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)NextEntry + (FreePages << PAGE_SHIFT)); 01225 do 01226 { 01227 // 01228 // Link back to the parent free entry, and keep going 01229 // 01230 NextEntry->Owner = FreeEntry; 01231 NextEntry->Signature = MM_FREE_POOL_SIGNATURE; 01232 NextEntry = (PMMFREE_POOL_ENTRY)((ULONG_PTR)NextEntry + PAGE_SIZE); 01233 } while (NextEntry != LastEntry); 01234 01235 /* Is freed non paged pool protected? */ 01236 if (MmProtectFreedNonPagedPool) 01237 { 01238 /* Protect the freed pool! */ 01239 MiProtectFreeNonPagedPool(FreeEntry, FreeEntry->Size); 01240 } 01241 01242 // 01243 // We're done, release the lock and let the caller know how much we freed 01244 // 01245 KeReleaseQueuedSpinLock(LockQueueMmNonPagedPoolLock, OldIrql); 01246 return NumberOfPages; 01247 } 01248 01249 01250 BOOLEAN 01251 NTAPI 01252 MiRaisePoolQuota(IN POOL_TYPE PoolType, 01253 IN ULONG CurrentMaxQuota, 01254 OUT PULONG NewMaxQuota) 01255 { 01256 // 01257 // Not implemented 01258 // 01259 UNIMPLEMENTED; 01260 *NewMaxQuota = CurrentMaxQuota + 65536; 01261 return TRUE; 01262 } 01263 01264 /* PUBLIC FUNCTIONS ***********************************************************/ 01265 01266 /* 01267 * @unimplemented 01268 */ 01269 PVOID 01270 NTAPI 01271 MmAllocateMappingAddress(IN SIZE_T NumberOfBytes, 01272 IN ULONG PoolTag) 01273 { 01274 UNIMPLEMENTED; 01275 return NULL; 01276 } 01277 01278 /* 01279 * @unimplemented 01280 */ 01281 VOID 01282 NTAPI 01283 MmFreeMappingAddress(IN PVOID BaseAddress, 01284 IN ULONG PoolTag) 01285 { 01286 UNIMPLEMENTED; 01287 } 01288 01289 /* EOF */ Generated on Sat May 26 2012 04:36:23 for ReactOS by
1.7.6.1
|