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

poolhack.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 pool.c 00008 00009 Abstract: 00010 00011 Implementation of the binary buddy pool allocator for the NT executive. 00012 00013 Author: 00014 00015 Mark Lucovsky 16-feb-1989 00016 00017 Environment: 00018 00019 kernel mode only 00020 00021 Revision History: 00022 00023 --*/ 00024 00025 00026 #if DBG 00027 //#define TRACE_ALLOC 1 00028 00029 #ifdef i386 00030 #define DEADBEEF 1 00031 #endif 00032 00033 #endif // DBG 00034 00035 #include "exp.h" 00036 #include "..\mm\mi.h" 00037 00038 // 00039 // Global Variables 00040 // 00041 00042 #ifdef TRACE_ALLOC 00043 PULONG RtlpGetFramePointer(VOID); 00044 00045 KSEMAPHORE TracePoolLock; 00046 LIST_ENTRY TracePoolListHead[MaxPoolType]; 00047 00048 typedef struct _TRACEBUFF { 00049 PVOID BufferAddress; 00050 PETHREAD Thread; 00051 PULONG xR1; 00052 PULONG xPrevR1; 00053 } TRACEBUFF, *PTRACEBUFF; 00054 00055 #define MAXTRACE 1024 00056 00057 ULONG NextAllocTrace; 00058 ULONG NextDeallocTrace; 00059 00060 TRACEBUFF AllocTrace[MAXTRACE]; 00061 TRACEBUFF DeallocTrace[MAXTRACE]; 00062 00063 00064 #endif //TRACE_ALLOC 00065 00066 #define POOL_PAGE_SIZE 0x1000 00067 #define POOL_LOG_PAGE 12 00068 #define POOL_LIST_HEADS 8 00069 #define POOL_LOG_MIN (POOL_LOG_PAGE - POOL_LIST_HEADS + 1) 00070 #define POOL_MIN_ROUND ( (1<<POOL_LOG_MIN) - 1 ) 00071 #define PAGE_ALIGNED(p) (!(((ULONG)p) & (POOL_PAGE_SIZE - 1))) 00072 00073 CHAR PoolIndexTable[128] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4, 00074 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 00075 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 00076 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 00077 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 00078 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 00079 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 00080 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 00081 }; 00082 00083 // 00084 // This structure exists in the pool descriptor structure. There is one of 00085 // these for each pool block size 00086 // 00087 00088 typedef struct _POOL_LIST_HEAD { 00089 ULONG CurrentFreeLength; 00090 ULONG Reserved; 00091 LIST_ENTRY ListHead; 00092 } POOL_LIST_HEAD; 00093 typedef POOL_LIST_HEAD *PPOOL_LIST_HEAD; 00094 00095 typedef struct _POOL_DESCRIPTOR { 00096 POOL_TYPE PoolType; 00097 ULONG TotalPages; 00098 ULONG Threshold; 00099 PVOID LockAddress; 00100 POOL_LIST_HEAD ListHeads[POOL_LIST_HEADS]; 00101 } POOL_DESCRIPTOR; 00102 typedef POOL_DESCRIPTOR *PPOOL_DESCRIPTOR; 00103 00104 typedef struct _POOL_HEADER { 00105 USHORT LogAllocationSize; 00106 USHORT PoolType; 00107 #ifdef TRACE_ALLOC 00108 LIST_ENTRY TraceLinks; 00109 PULONG xR1; 00110 PULONG xPrevR1; 00111 #endif // TRACE_ALLOC 00112 EPROCESS *ProcessBilled; 00113 } POOL_HEADER; 00114 typedef POOL_HEADER *PPOOL_HEADER; 00115 00116 #define POOL_OVERHEAD sizeof(POOL_HEADER) 00117 #define POOL_BUDDY_MAX (POOL_PAGE_SIZE - POOL_OVERHEAD) 00118 00119 POOL_DESCRIPTOR NonPagedPoolDescriptor,PagedPoolDescriptor; 00120 POOL_DESCRIPTOR NonPagedPoolDescriptorMS,PagedPoolDescriptorMS; 00121 00122 KSPIN_LOCK NonPagedPoolLock; 00123 KMUTEX PagedPoolLock; 00124 00125 00126 PPOOL_DESCRIPTOR PoolVector[MaxPoolType] = { 00127 &NonPagedPoolDescriptor, 00128 &PagedPoolDescriptor, 00129 &NonPagedPoolDescriptorMS, 00130 &PagedPoolDescriptorMS 00131 }; 00132 00133 POOL_TYPE BasePoolTypeTable[MaxPoolType] = { 00134 NonPagedPool, 00135 PagedPool, 00136 NonPagedPool, 00137 PagedPool 00138 }; 00139 00140 BOOLEAN MustSucceedPoolTable[MaxPoolType] = { 00141 FALSE, 00142 FALSE, 00143 TRUE, 00144 TRUE 00145 }; 00146 00147 00148 PPOOL_HEADER 00149 AllocatePoolInternal( 00150 IN PPOOL_DESCRIPTOR PoolDesc, 00151 IN LONG Index 00152 ); 00153 00154 VOID 00155 DeallocatePoolInternal( 00156 IN PPOOL_DESCRIPTOR PoolDesc, 00157 IN PPOOL_HEADER Entry 00158 ); 00159 00160 PLIST_ENTRY 00161 ExpInterlockedTryAllocatePool( 00162 IN PLIST_ENTRY List, 00163 IN KSPIN_LOCK Lock, 00164 IN ULONG Size, 00165 IN LONG SizeOffset 00166 ); 00167 00168 00169 // 00170 // LOCK_POOL is used as a macro only within this module 00171 // 00172 00173 #define LOCK_POOL(Lock,PoolType,LockHandle) \ 00174 { \ 00175 if ( (PoolType) == (NonPagedPool) || (PoolType) == NonPagedPoolMustSucceed ) { \ 00176 KeAcquireSpinLock((PKSPIN_LOCK)Lock,&LockHandle); \ 00177 } else { \ 00178 KeRaiseIrql(APC_LEVEL,&LockHandle); \ 00179 KeWaitForSingleObject( \ 00180 Lock, \ 00181 PoolAllocation, \ 00182 KernelMode, \ 00183 FALSE, \ 00184 NULL \ 00185 ); \ 00186 } \ 00187 } 00188 00189 KIRQL 00190 ExLockPool( 00191 IN POOL_TYPE PoolType 00192 ) 00193 00194 /*++ 00195 00196 Routine Description: 00197 00198 This function locks the pool specified by pool type. 00199 00200 Arguments: 00201 00202 PoolType - Specifies the pool that should be locked. 00203 00204 Return Value: 00205 00206 Opaque - Returns a lock handle that must be returned in a subsequent 00207 call to ExUnlockPool. 00208 00209 --*/ 00210 00211 { 00212 00213 KIRQL Irql; 00214 00215 if ( PoolType == NonPagedPool || PoolType == NonPagedPoolMustSucceed ) { 00216 00217 // 00218 // Spin Lock locking 00219 // 00220 00221 KeAcquireSpinLock((PKSPIN_LOCK)PoolVector[PoolType]->LockAddress, &Irql); 00222 return Irql; 00223 } else { 00224 00225 // 00226 // Mutex Locking 00227 // 00228 00229 KeRaiseIrql(APC_LEVEL, &Irql); 00230 00231 KeWaitForSingleObject( 00232 PoolVector[PoolType]->LockAddress, 00233 PoolAllocation, 00234 KernelMode, 00235 FALSE, 00236 NULL 00237 ); 00238 00239 return Irql; 00240 } 00241 00242 } 00243 00244 // 00245 // UNLOCK_POOL is used as a macro only within this module 00246 // 00247 00248 #define UNLOCK_POOL(Lock,PoolType,LockHandle,Wait) \ 00249 { \ 00250 if ( PoolType == NonPagedPool || (PoolType) == NonPagedPoolMustSucceed ) { \ 00251 KeReleaseSpinLock( \ 00252 Lock, \ 00253 (KIRQL)LockHandle \ 00254 ); \ 00255 } else { \ 00256 KeReleaseMutex((PKMUTEX)Lock,Wait); \ 00257 KeLowerIrql(LockHandle); \ 00258 } \ 00259 } 00260 00261 VOID 00262 ExUnlockPool( 00263 IN POOL_TYPE PoolType, 00264 IN KIRQL LockHandle, 00265 IN BOOLEAN Wait 00266 ) 00267 00268 /*++ 00269 00270 Routine Description: 00271 00272 This function unlocks the pool specified by pool type. If the value 00273 of the Wait parameter is true, then the pool's lock is released 00274 using "wait == true". 00275 00276 00277 Arguments: 00278 00279 PoolType - Specifies the pool that should be unlocked. 00280 00281 LockHandle - Specifies the lock handle from a previous call to 00282 ExLockPool. 00283 00284 Wait - Supplies a boolean value that signifies whether the call to 00285 ExUnlockPool will be immediately followed by a call to one of 00286 the kernel Wait functions. 00287 00288 Return Value: 00289 00290 None. 00291 00292 --*/ 00293 00294 { 00295 00296 if ( PoolType == NonPagedPool || (PoolType) == NonPagedPoolMustSucceed ) { 00297 00298 // 00299 // Spin Lock locking 00300 // 00301 00302 KeReleaseSpinLock( 00303 (PKSPIN_LOCK)PoolVector[PoolType]->LockAddress, 00304 LockHandle 00305 ); 00306 00307 } else { 00308 00309 // 00310 // Mutex Locking 00311 // 00312 00313 KeReleaseMutex((PKMUTEX)PoolVector[PoolType]->LockAddress,Wait); 00314 00315 // 00316 // This could be a problem if wait == true is specified ! 00317 // 00318 00319 KeLowerIrql(LockHandle); 00320 } 00321 00322 } 00323 00324 VOID 00325 InitializePool( 00326 IN POOL_TYPE PoolType, 00327 IN ULONG Threshold 00328 ) 00329 00330 /*++ 00331 00332 Routine Description: 00333 00334 This procedure initializes a pool descriptor for a binary buddy pool 00335 type. Once initialized, the pool may be used for allocation and 00336 deallocation. 00337 00338 This function should be called once for each base pool type during 00339 system initialization. 00340 00341 Each pool descriptor contains an array of list heads for free 00342 blocks. Each list head holds blocks of a particular size. One list 00343 head contains page-sized blocks. The other list heads contain 1/2- 00344 page-sized blocks, 1/4-page-sized blocks.... A threshold is 00345 associated with the page-sized list head. The number of free blocks 00346 on this list will not grow past the specified threshold. When a 00347 deallocation occurs that would cause the threshold to be exceeded, 00348 the page is returned to the page-aliged pool allocator. 00349 00350 Arguments: 00351 00352 PoolType - Supplies the type of pool being initialized (e.g. 00353 nonpaged pool, paged pool...). 00354 00355 Threshold - Supplies the threshold value for the specified pool. 00356 00357 Return Value: 00358 00359 None. 00360 00361 --*/ 00362 00363 { 00364 int i; 00365 POOL_TYPE BasePoolType, MustSucceedPoolType; 00366 00367 if ( MustSucceedPoolTable[PoolType] ) { 00368 KeBugCheck(PHASE0_INITIALIZATION_FAILED); 00369 } 00370 00371 if (PoolType == NonPagedPool) { 00372 00373 BasePoolType = NonPagedPool; 00374 MustSucceedPoolType = NonPagedPoolMustSucceed; 00375 00376 KeInitializeSpinLock(&PsGetCurrentProcess()->StatisticsLock); 00377 KeInitializeSpinLock(&NonPagedPoolLock); 00378 NonPagedPoolDescriptor.LockAddress = (PVOID)&NonPagedPoolLock; 00379 NonPagedPoolDescriptorMS.LockAddress = (PVOID)&NonPagedPoolLock; 00380 00381 KeInitializeMutex(&PagedPoolLock,MUTEX_LEVEL_EX_PAGED_POOL); 00382 PagedPoolDescriptor.LockAddress = (PVOID)&PagedPoolLock; 00383 PagedPoolDescriptorMS.LockAddress = (PVOID)&PagedPoolLock; 00384 00385 #ifdef TRACE_ALLOC 00386 00387 KeInitializeSemaphore(&TracePoolLock,1L,1L); 00388 InitializeListHead(&TracePoolListHead[NonPagedPool]); 00389 InitializeListHead(&TracePoolListHead[PagedPool]); 00390 00391 #endif // TRACE_ALLOC 00392 } else { 00393 BasePoolType = PagedPool; 00394 MustSucceedPoolType = PagedPoolMustSucceed; 00395 } 00396 00397 PoolVector[BasePoolType]->TotalPages = 0; 00398 PoolVector[BasePoolType]->Threshold = Threshold; 00399 PoolVector[BasePoolType]->PoolType = BasePoolType; 00400 PoolVector[MustSucceedPoolType]->TotalPages = 0; 00401 PoolVector[MustSucceedPoolType]->Threshold = 0; 00402 PoolVector[MustSucceedPoolType]->PoolType = MustSucceedPoolType; 00403 for (i=0; i<POOL_LIST_HEADS ;i++ ) { 00404 InitializeListHead(&PoolVector[BasePoolType]->ListHeads[i].ListHead); 00405 PoolVector[BasePoolType]->ListHeads[i].CurrentFreeLength = 0; 00406 InitializeListHead(&PoolVector[MustSucceedPoolType]->ListHeads[i].ListHead); 00407 PoolVector[MustSucceedPoolType]->ListHeads[i].CurrentFreeLength = 0; 00408 } 00409 return; 00410 } 00411 00412 PVOID 00413 ExAllocatePool( 00414 IN POOL_TYPE PoolType, 00415 IN ULONG NumberOfBytes 00416 ) 00417 00418 /*++ 00419 00420 Routine Description: 00421 00422 This function allocates a block of pool of the specified type and 00423 returns a pointer to the allocated block. This function is used to 00424 access both the page-aligned pools, and the binary buddy (less than 00425 a page) pools. 00426 00427 If the number of bytes specifies a size that is too large to be 00428 satisfied by the appropriate binary buddy pool, then the page-aligned 00429 pool allocator is used. The allocated block will be page-aligned 00430 and a page-sized multiple. 00431 00432 Otherwise, the appropriate binary buddy pool is used. The allocated 00433 block will be 64-bit aligned, but will not be page aligned. The 00434 binary buddy allocator calculates the smallest block size that is a 00435 power of two and that can be used to satisfy the request. If there 00436 are no blocks available of this size, then a block of the next 00437 larger block size is allocated and split in half. One piece is 00438 placed back into the pool, and the other piece is used to satisfy 00439 the request. If the allocator reaches the paged-sized block list, 00440 and nothing is there, the page-aligned pool allocator is called. 00441 The page is added to the binary buddy pool... 00442 00443 Arguments: 00444 00445 PoolType - Supplies the type of pool to allocate. If the pool type 00446 is one of the "MustSucceed" pool types, then this call will 00447 always succeed and return a pointer to allocated pool. 00448 Otherwise, if the system can not allocate the requested amount 00449 of memory a NULL is returned. 00450 00451 NumberOfBytes - Supplies the number of bytes to allocate. 00452 00453 Return Value: 00454 00455 NULL - The PoolType is not one of the "MustSucceed" pool types, and 00456 not enough pool exists to satisfy the request. 00457 00458 NON-NULL - Returns a pointer to the allocated pool. 00459 00460 --*/ 00461 00462 { 00463 PPOOL_HEADER Entry; 00464 PEPROCESS CurrentProcess; 00465 KIRQL LockHandle; 00466 PPOOL_DESCRIPTOR PoolDesc; 00467 PVOID Lock; 00468 LONG Index; 00469 PVOID Block; 00470 00471 KIRQL OldIrql; 00472 PMMPTE PointerPte; 00473 ULONG PageFrameIndex; 00474 MMPTE TempPte; 00475 BOOLEAN ReleaseSpinLock = TRUE; 00476 00477 #if defined(TRACE_ALLOC) || defined (DEADBEEF) 00478 00479 PULONG BadFood; 00480 #endif //TRACE_ALLOC 00481 00482 #ifdef TRACE_ALLOC 00483 PULONG xFp, xPrevFp, xR1, xPrevR1, xPrevPrevR1; 00484 00485 xFp = RtlpGetFramePointer(); 00486 xR1 = (PULONG)*(xFp+1); 00487 xPrevFp = (PULONG)*xFp; 00488 xPrevR1 = (PULONG)*(xPrevFp+1); 00489 xPrevFp = (PULONG)*xPrevFp; 00490 xPrevPrevR1 = (PULONG)*(xPrevFp+1); 00491 00492 #endif // TRACE_ALLOC 00493 00494 00495 00496 PoolDesc = PoolVector[PoolType]; 00497 Lock = PoolDesc->LockAddress; 00498 00499 if (NumberOfBytes > POOL_BUDDY_MAX) { 00500 00501 LOCK_POOL(Lock,PoolType,LockHandle); 00502 00503 Entry = (PPOOL_HEADER)MiAllocatePoolPages ( 00504 BasePoolTypeTable[PoolType], 00505 NumberOfBytes 00506 ); 00507 if ( !Entry && MustSucceedPoolTable[PoolType] ) { 00508 Entry = (PPOOL_HEADER)MiAllocatePoolPages ( 00509 PoolType, 00510 NumberOfBytes 00511 ); 00512 } 00513 UNLOCK_POOL(Lock,PoolType,LockHandle,FALSE); 00514 00515 return Entry; 00516 } 00517 00518 if (KeGetCurrentIrql() >= 2) { 00519 DbgPrint("allocating pool at irql >= 2\n"); 00520 ReleaseSpinLock = FALSE; 00521 00522 } else { 00523 KeAcquireQueuedSpinLock(LockQueuePfnLock); 00524 } 00525 00526 PointerPte = MiReserveSystemPtes (2, SystemPteSpace, 0, 0, TRUE); 00527 00528 ASSERT (MmAvailablePages > 0); 00529 PageFrameIndex = MiRemoveAnyPage (); 00530 TempPte = ValidKernelPte; 00531 TempPte.u.Hard.PageFrameNumber = PageFrameIndex; 00532 *PointerPte = TempPte; 00533 MiInitializePfn (PageFrameIndex, PointerPte, 1L, 1); 00534 00535 if (ReleaseSpinLock) { 00536 KeReleaseSpinLock ( &MmPfnLock, OldIrql ); 00537 } 00538 00539 Entry = (PVOID)MiGetVirtualAddressMappedByPte (PointerPte); 00540 00541 Entry = (PVOID)(((ULONG)Entry + (PAGE_SIZE - (NumberOfBytes))) & 00542 0xfffffff8L); 00543 00544 return Entry; 00545 00546 00547 Index = ( (NumberOfBytes+POOL_OVERHEAD+POOL_MIN_ROUND) >> POOL_LOG_MIN) - 1; 00548 00549 Index = PoolIndexTable[Index]; 00550 00551 LOCK_POOL(Lock,PoolType,LockHandle); 00552 00553 if ( !IsListEmpty(&PoolDesc->ListHeads[Index].ListHead) ) { 00554 00555 Block = RemoveHeadList(&PoolDesc->ListHeads[Index].ListHead); 00556 Entry = (PPOOL_HEADER) ((PCH)Block - POOL_OVERHEAD); 00557 Entry->ProcessBilled = (PEPROCESS)NULL; 00558 Entry->LogAllocationSize = (USHORT)POOL_LOG_MIN + Index; 00559 Entry->PoolType = (USHORT)PoolType; 00560 #if defined(TRACE_ALLOC) || defined (DEADBEEF) 00561 BadFood = (PULONG)Block; 00562 *BadFood = 0xBAADF00D; 00563 *(BadFood+1) = 0xBAADF00D; 00564 #endif // TRACE_ALLOC 00565 00566 } else { 00567 00568 Entry = AllocatePoolInternal(PoolDesc,Index); 00569 00570 if ( !Entry ) { 00571 #if DBG 00572 DbgPrint("EX: ExAllocatePool returning NULL\n"); 00573 DbgBreakPoint(); 00574 #endif // DBG 00575 UNLOCK_POOL(Lock,PoolType,LockHandle,FALSE); 00576 return NULL; 00577 } 00578 } 00579 00580 UNLOCK_POOL(Lock,PoolType,LockHandle,FALSE); 00581 00582 #ifdef TRACE_ALLOC 00583 { 00584 KIRQL xIrql; 00585 00586 KeRaiseIrql(APC_LEVEL, &xIrql); 00587 00588 KeWaitForSingleObject( 00589 &TracePoolLock, 00590 PoolAllocation, 00591 KernelMode, 00592 FALSE, 00593 NULL 00594 ); 00595 00596 InsertTailList(&TracePoolListHead[PoolType],&Entry->TraceLinks); 00597 00598 Entry->xR1 = xR1; 00599 Entry->xPrevR1 = xPrevR1; 00600 Entry->ProcessBilled = (PEPROCESS)xPrevPrevR1; 00601 00602 //Entry->ProcessBilled = (PEPROCESS)NextAllocTrace; 00603 00604 AllocTrace[NextAllocTrace].BufferAddress = (PCH)Entry + POOL_OVERHEAD; 00605 AllocTrace[NextAllocTrace].Thread = PsGetCurrentThread(); 00606 AllocTrace[NextAllocTrace].xR1 = xR1; 00607 AllocTrace[NextAllocTrace++].xPrevR1 = xPrevR1; 00608 if ( NextAllocTrace >= MAXTRACE ) { 00609 NextAllocTrace = 0; 00610 } 00611 00612 00613 (VOID) KeReleaseSemaphore( 00614 &TracePoolLock, 00615 0L, 00616 1L, 00617 FALSE 00618 ); 00619 KeLowerIrql(xIrql); 00620 00621 } 00622 #endif // TRACE_ALLOC 00623 00624 #if defined(TRACE_ALLOC) || defined (DEADBEEF) 00625 { 00626 PULONG NewPool; 00627 ULONG LongCount; 00628 00629 Block = (PULONG)((PCH)Entry + POOL_OVERHEAD); 00630 NewPool = (PULONG) ((PCH)Entry + POOL_OVERHEAD); 00631 LongCount = (1 << Entry->LogAllocationSize) >> 2; 00632 LongCount -= (POOL_OVERHEAD>>2); 00633 00634 while(LongCount--) { 00635 if ( *NewPool != 0xBAADF00D ) { 00636 DbgPrint("ExAllocatePool: No BAADF00D Block %lx at %lx\n", 00637 Block, 00638 NewPool 00639 ); 00640 KeBugCheck(0xBADF00D2); 00641 } 00642 *NewPool++ = 0xDEADBEEF; 00643 } 00644 } 00645 #endif //TRACE_ALLOC 00646 00647 return ((PCH)Entry + POOL_OVERHEAD); 00648 } 00649 00650 ULONG 00651 ExpAllocatePoolWithQuotaHandler( 00652 IN NTSTATUS ExceptionCode, 00653 IN PVOID PoolAddress 00654 ) 00655 00656 /*++ 00657 00658 Routine Description: 00659 00660 This function is called when an exception occurs in ExFreePool 00661 while quota is being charged to a process. 00662 00663 Its function is to deallocate the pool block and continue the search 00664 for an exception handler. 00665 00666 Arguments: 00667 00668 ExceptionCode - Supplies the exception code that caused this 00669 function to be entered. 00670 00671 PoolAddress - Supplies the address of a pool block that needs to be 00672 deallocated. 00673 00674 Return Value: 00675 00676 EXCEPTION_CONTINUE_SEARCH - The exception should be propagated to the 00677 caller of ExAllocatePoolWithQuota. 00678 00679 --*/ 00680 00681 { 00682 if ( PoolAddress ) { 00683 ASSERT(ExceptionCode == STATUS_QUOTA_EXCEEDED); 00684 ExFreePool(PoolAddress); 00685 } else { 00686 ASSERT(ExceptionCode == STATUS_INSUFFICIENT_RESOURCES); 00687 } 00688 return EXCEPTION_CONTINUE_SEARCH; 00689 } 00690 00691 00692 00693 PVOID 00694 ExAllocatePoolWithQuota( 00695 IN POOL_TYPE PoolType, 00696 IN ULONG NumberOfBytes 00697 ) 00698 00699 /*++ 00700 00701 Routine Description: 00702 00703 This function allocates a block of pool of the specified type, 00704 returns a pointer to the allocated block, and if the binary buddy 00705 allocator was used to satisfy the request, charges pool quota to the 00706 current process. This function is used to access both the 00707 page-aligned pools, and the binary buddy. 00708 00709 If the number of bytes specifies a size that is too large to be 00710 satisfied by the appropriate binary buddy pool, then the 00711 page-aligned pool allocator is used. The allocated block will be 00712 page-aligned and a page-sized multiple. No quota is charged to the 00713 current process if this is the case. 00714 00715 Otherwise, the appropriate binary buddy pool is used. The allocated 00716 block will be 64-bit aligned, but will not be page aligned. After 00717 the allocation completes, an attempt will be made to charge pool 00718 quota (of the appropriate type) to the current process object. If 00719 the quota charge succeeds, then the pool block's header is adjusted 00720 to point to the current process. The process object is not 00721 dereferenced until the pool is deallocated and the appropriate 00722 amount of quota is returned to the process. Otherwise, the pool is 00723 deallocated, a "quota exceeded" condition is raised. 00724 00725 Arguments: 00726 00727 PoolType - Supplies the type of pool to allocate. If the pool type 00728 is one of the "MustSucceed" pool types and sufficient quota 00729 exists, then this call will always succeed and return a pointer 00730 to allocated pool. Otherwise, if the system can not allocate 00731 the requested amount of memory a STATUS_INSUFFICIENT_RESOURCES 00732 status is raised. 00733 00734 NumberOfBytes - Supplies the number of bytes to allocate. 00735 00736 Return Value: 00737 00738 NON-NULL - Returns a pointer to the allocated pool. 00739 00740 Unspecified - If insuffient quota exists to complete the pool 00741 allocation, the return value is unspecified. 00742 00743 --*/ 00744 00745 { 00746 PVOID p; 00747 PEPROCESS Process; 00748 PPOOL_HEADER Entry; 00749 ULONG AllocationSize; 00750 00751 p = ExAllocatePool(PoolType,NumberOfBytes); 00752 00753 00754 #ifndef TRACE_ALLOC 00755 if ( p && !PAGE_ALIGNED(p) ) { 00756 00757 Entry = (PPOOL_HEADER)((PCH)p - POOL_OVERHEAD); 00758 00759 Process = PsGetCurrentProcess(); 00760 00761 // 00762 // Catch exception and back out allocation if necessary 00763 // 00764 00765 try { 00766 00767 PsChargePoolQuota(Process,BasePoolTypeTable[PoolType],(1 << Entry->LogAllocationSize)); 00768 ObReferenceObject(Process); 00769 Entry->ProcessBilled = Process; 00770 00771 } except ( ExpAllocatePoolWithQuotaHandler(GetExceptionCode(),p)) { 00772 KeBugCheck(GetExceptionCode()); 00773 } 00774 00775 } else { 00776 if ( !p ) { 00777 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 00778 } 00779 } 00780 #endif // TRACE_ALLOC 00781 00782 return p; 00783 } 00784 00785 PPOOL_HEADER 00786 AllocatePoolInternal( 00787 IN PPOOL_DESCRIPTOR PoolDesc, 00788 IN LONG Index 00789 ) 00790 00791 /*++ 00792 00793 Routine Description: 00794 00795 This function implements the guts of the binary buddy pool 00796 allocator. It is a recursive function. It assumes that the caller 00797 (ExAllocatePool) chose the correct pool descriptor, and that the 00798 allocation should be satisfied from the binary buddy allocator. 00799 00800 The binary buddy allocator calculates the smallest block size that 00801 is a power of two and that can be used to satisfy the request. If 00802 there are no blocks available of this size, then a block of the next 00803 larger block size is allocated and split in half. One piece is 00804 placed back into the pool, and the other piece is used to satisfy 00805 the request. If the allocator reaches the paged sized block list, 00806 and nothing is there, the page aligned pool allocator is called. 00807 The page is added to the binary buddy pool... 00808 00809 Arguments: 00810 00811 PoolDesc - Supplies the address of the pool descriptor to use to 00812 satisfy the request. 00813 00814 Index - Supplies the index into the pool descriptor list head array 00815 that should satisfy an allocation. 00816 00817 Return Value: 00818 00819 Non-Null - Returns a pointer to the allocated pool header. Before 00820 this can be returned to the caller of ExAllocatePool or 00821 ExAllocatePoolWithQuota, the value must be adjusted 00822 (incremented) to account for the 64bit binary buddy pool 00823 overhead. 00824 00825 --*/ 00826 00827 { 00828 LONG Log2N,ShiftedN; 00829 PPOOL_HEADER Entry,Buddy; 00830 PPOOL_LIST_HEAD PoolListHead; 00831 00832 #if defined(TRACE_ALLOC) || defined (DEADBEEF) 00833 PULONG BadFood; 00834 #endif // TRACE_ALLOC 00835 00836 Log2N = POOL_LOG_MIN + Index; 00837 ShiftedN = 1 << Log2N; 00838 00839 PoolListHead = &PoolDesc->ListHeads[Index]; 00840 00841 // 00842 // this is the correct list head. See if anything is on the 00843 // list if so, delink and mark as allocated. Otherwise, 00844 // recurse and split. 00845 // 00846 00847 if ( !IsListEmpty(&PoolListHead->ListHead) ) { 00848 00849 // 00850 // list has an entry, so grab it 00851 // 00852 00853 Entry = (PPOOL_HEADER)RemoveHeadList( 00854 &PoolListHead->ListHead); 00855 00856 #if defined(TRACE_ALLOC) || defined (DEADBEEF) 00857 BadFood = (PULONG)Entry; 00858 *BadFood = 0xBAADF00D; 00859 *(BadFood+1) = 0xBAADF00D; 00860 #endif // TRACE_ALLOC 00861 00862 Entry = (PPOOL_HEADER) ((PCH)Entry - POOL_OVERHEAD); 00863 00864 // 00865 // allocated entries have a size field set and pool type set 00866 // 00867 00868 Entry->LogAllocationSize = (USHORT)Log2N; 00869 Entry->PoolType = PoolDesc->PoolType; 00870 Entry->ProcessBilled = (PEPROCESS)NULL; 00871 00872 return (PVOID)Entry; 00873 00874 } else { 00875 00876 if ( Index != (POOL_LIST_HEADS - 1) ) { 00877 00878 // 00879 // This is the right list head, but since it is empty 00880 // must recurse. Allocate from the next highest entry. 00881 // The resulting entry is then split in half. One half 00882 // is marked as free and added to the list. The other 00883 // half is returned 00884 // 00885 00886 Entry = (PPOOL_HEADER)AllocatePoolInternal(PoolDesc,Index+1); 00887 00888 if ( !Entry ) { 00889 return NULL; 00890 } 00891 00892 #if defined(TRACE_ALLOC) || defined (DEADBEEF) 00893 BadFood = (PULONG)((PCH)Entry + POOL_OVERHEAD); 00894 *BadFood = 0xBAADF00D; 00895 *(BadFood+1) = 0xBAADF00D; 00896 #endif // TRACE_ALLOC 00897 00898 Buddy = (PPOOL_HEADER)((PCH)Entry + ShiftedN); 00899 00900 // 00901 // mark buddy as free and entry as allocated 00902 // 00903 00904 Entry->LogAllocationSize = (USHORT) Log2N; 00905 Entry->PoolType = PoolDesc->PoolType; 00906 Entry->ProcessBilled = (PEPROCESS)NULL; 00907 00908 Buddy->LogAllocationSize = 0; 00909 Buddy->PoolType = Index; 00910 Buddy->ProcessBilled = (PEPROCESS)NULL; 00911 00912 InsertTailList( 00913 &PoolListHead->ListHead, 00914 (PLIST_ENTRY)(((PCH)Buddy + POOL_OVERHEAD)) 00915 ); 00916 00917 return (PVOID)Entry; 00918 00919 } else { 00920 00921 // 00922 // Need to call page allocator for a page to add to the pool 00923 // 00924 00925 Entry = (PPOOL_HEADER)MiAllocatePoolPages ( 00926 BasePoolTypeTable[PoolDesc->PoolType], 00927 PAGE_SIZE 00928 ); 00929 00930 if ( !Entry ) { 00931 if ( MustSucceedPoolTable[PoolDesc->PoolType] ) { 00932 Entry = (PPOOL_HEADER)MiAllocatePoolPages ( 00933 PoolDesc->PoolType, 00934 PAGE_SIZE 00935 ); 00936 ASSERT(Entry); 00937 } else { 00938 return NULL; 00939 } 00940 } 00941 00942 Entry->LogAllocationSize = (USHORT) Log2N; 00943 Entry->PoolType = PoolDesc->PoolType; 00944 Entry->ProcessBilled = (PEPROCESS)NULL; 00945 00946 #if defined(TRACE_ALLOC) || defined (DEADBEEF) 00947 { 00948 PULONG NewPool; 00949 ULONG LongCount; 00950 00951 NewPool = (PULONG) ((PCH)Entry + POOL_OVERHEAD); 00952 LongCount = (1 << Entry->LogAllocationSize) >> 2; 00953 LongCount -= (POOL_OVERHEAD>>2); 00954 00955 while(LongCount--) { 00956 *NewPool++ = 0xBAADF00D; 00957 } 00958 } 00959 #endif //TRACE_ALLOC 00960 00961 PoolDesc->TotalPages++; 00962 00963 return (PVOID)Entry; 00964 00965 } 00966 } 00967 } 00968 00969 VOID 00970 ExFreePool( 00971 IN PVOID P 00972 ) 00973 00974 /*++ 00975 00976 Routine Description: 00977 00978 This function deallocates a block of pool. This function is used to 00979 deallocate to both the page aligned pools, and the binary buddy 00980 (less than a page) pools. 00981 00982 If the address of the block being deallocated is page-aligned, then 00983 the page-aliged pool deallocator is used. 00984 00985 Otherwise, the binary buddy pool deallocator is used. Deallocation 00986 looks at the allocated block's pool header to determine the pool 00987 type and block size being deallocated. If the pool was allocated 00988 using ExAllocatePoolWithQuota, then after the deallocation is 00989 complete, the appropriate process's pool quota is adjusted to reflect 00990 the deallocation, and the process object is dereferenced. 00991 00992 Arguments: 00993 00994 P - Supplies the address of the block of pool being deallocated. 00995 00996 Return Value: 00997 00998 None. 00999 01000 --*/ 01001 01002 { 01003 PPOOL_HEADER Entry; 01004 POOL_TYPE PoolType; 01005 KIRQL LockHandle; 01006 PVOID Lock; 01007 PPOOL_DESCRIPTOR PoolDesc; 01008 01009 KIRQL OldIrql; 01010 BOOLEAN ReleaseSpinLock = TRUE; 01011 PMMPTE PointerPte; 01012 PMMPFN Pfn1; 01013 01014 #ifdef TRACE_ALLOC 01015 01016 PULONG xFp, xPrevFp, xR1, xPrevR1; 01017 01018 xFp = RtlpGetFramePointer(); 01019 xR1 = (PULONG)*(xFp+1); 01020 xPrevFp = (PULONG)*xFp; 01021 xPrevR1 = (PULONG)*(xPrevFp+1); 01022 01023 #endif // TRACE_ALLOC 01024 01025 // 01026 // If Entry is page aligned, then call page aligned pool 01027 // 01028 01029 if ( PAGE_ALIGNED(P) ) { 01030 01031 PoolType = MmDeterminePoolType(P); 01032 01033 Lock = PoolVector[PoolType]->LockAddress; 01034 01035 LOCK_POOL(Lock,PoolType,LockHandle); 01036 MiFreePoolPages (P); 01037 UNLOCK_POOL(Lock,PoolType,LockHandle,FALSE); 01038 return; 01039 } 01040 01041 PointerPte = MiGetPteAddress (P); 01042 01043 if (PointerPte->u.Hard.Valid == 0) { 01044 DbgPrint("bad pool deallocation\n"); 01045 KeBugCheck (12345); 01046 } 01047 01048 if (KeGetCurrentIrql() >= 2) { 01049 DbgPrint("deallocating pool at irql >= 2\n"); 01050 ReleaseSpinLock = FALSE; 01051 } else { 01052 KeAcquireSpinLock ( &MmPfnLock, &OldIrql); 01053 } 01054 01055 KeSweepDcache(TRUE); 01056 01057 Pfn1 = MI_PFN_ELEMENT (PointerPte->u.Hard.PageFrameNumber); 01058 Pfn1->PteAddress = (PMMPTE)MM_EMPTY_LIST; 01059 MiDecrementShareCountOnly (PointerPte->u.Hard.PageFrameNumber); 01060 *PointerPte = ZeroPte; 01061 MiReleaseSystemPtes (PointerPte, 2, SystemPteSpace); 01062 // 01063 // BUGBUG Fix for MP. 01064 // 01065 KiFlushSingleTb (P,TRUE); 01066 if (ReleaseSpinLock) { 01067 KeReleaseSpinLock ( &MmPfnLock, OldIrql ); 01068 } 01069 return; 01070 01071 Entry = (PPOOL_HEADER)((PCH)P - POOL_OVERHEAD); 01072 01073 PoolType = Entry->PoolType; 01074 01075 PoolDesc = PoolVector[PoolType]; 01076 Lock = PoolDesc->LockAddress; 01077 01078 // 01079 // Sanity Check pool header 01080 // 01081 01082 if ( (Entry->LogAllocationSize == 0) || (Entry->PoolType >= MaxPoolType) ) { 01083 DbgPrint("Invalid pool header 0x%lx 0x%lx\n",P,*(PULONG)P); 01084 KeBugCheck(BAD_POOL_HEADER); 01085 return; 01086 } 01087 01088 if ( (ULONG)P & 0x0000000f != 8 ) { 01089 DbgPrint("Misaligned Deallocation 0x%lx\n",P); 01090 KeBugCheck(BAD_POOL_HEADER); 01091 return; 01092 } 01093 01094 #ifdef TRACE_ALLOC 01095 { 01096 KIRQL xIrql; 01097 PLIST_ENTRY Next, Target; 01098 BOOLEAN Found; 01099 01100 KeRaiseIrql(APC_LEVEL, &xIrql); 01101 01102 KeWaitForSingleObject( 01103 &TracePoolLock, 01104 PoolAllocation, 01105 KernelMode, 01106 FALSE, 01107 NULL 01108 ); 01109 01110 Found = FALSE; 01111 Target = &Entry->TraceLinks; 01112 Next = TracePoolListHead[PoolType].Flink; 01113 while( Next != &TracePoolListHead[PoolType] ){ 01114 if ( Next == Target ) { 01115 01116 RemoveEntryList(&Entry->TraceLinks); 01117 Found = TRUE; 01118 break; 01119 } 01120 Next = Next->Flink; 01121 } 01122 01123 if ( !Found ) { 01124 DbgPrint("Block Not in Allocated Pool List 0x%lx\n",P); 01125 KeBugCheck(BAD_POOL_HEADER); 01126 return; 01127 } 01128 01129 DeallocTrace[NextDeallocTrace].BufferAddress = P; 01130 DeallocTrace[NextDeallocTrace].Thread = PsGetCurrentThread(); 01131 DeallocTrace[NextDeallocTrace].xR1 = xR1; 01132 DeallocTrace[NextDeallocTrace++].xPrevR1 = xPrevR1; 01133 if ( NextDeallocTrace >= MAXTRACE ) { 01134 NextDeallocTrace = 0; 01135 } 01136 01137 (VOID) KeReleaseSemaphore( 01138 &TracePoolLock, 01139 0L, 01140 1L, 01141 FALSE 01142 ); 01143 KeLowerIrql(xIrql); 01144 01145 } 01146 #endif // TRACE_ALLOC 01147 01148 #ifndef TRACE_ALLOC 01149 01150 // 01151 // Check ProcessBilled flag to see if quota was charged on 01152 // this allocation 01153 // 01154 01155 if ( Entry->ProcessBilled ) { 01156 01157 PsReturnPoolQuota( 01158 Entry->ProcessBilled, 01159 BasePoolTypeTable[PoolType], 01160 (1 << Entry->LogAllocationSize) 01161 ); 01162 01163 ObDereferenceObject(Entry->ProcessBilled); 01164 01165 } 01166 #endif // TRACE_ALLOC 01167 01168 LOCK_POOL(Lock,PoolType,LockHandle); 01169 01170 DeallocatePoolInternal(PoolDesc,Entry); 01171 01172 UNLOCK_POOL(Lock,PoolType,LockHandle,FALSE); 01173 01174 } 01175 01176 VOID 01177 DeallocatePoolInternal( 01178 IN PPOOL_DESCRIPTOR PoolDesc, 01179 IN PPOOL_HEADER Entry 01180 ) 01181 01182 /*++ 01183 01184 Routine Description: 01185 01186 This function implements the guts of the binary buddy pool 01187 deallocator. It is a recursive function. It assumes that the 01188 caller (ExFreePool) chose the correct pool descriptor, and that 01189 the deallocation should be done using the binary buddy deallocator. 01190 01191 The binary buddy deallocator automatically collapses adjacent free 01192 blocks of the same size into a single free block of the next larger 01193 size. This is a recursive operation. This does not occur on a 01194 deallocation of a page sized block. If a page sized block is being 01195 deallocated, then the pool descriptor's threshold is examined. If 01196 the deallocation would cause the threshold to be exceeded, the page 01197 sized block is returned to the page aligned pool allocator. 01198 01199 Arguments: 01200 01201 PoolDesc - Supplies the address of the pool descriptor to use to 01202 satisfy the request. 01203 01204 Entry - Supplies the address of the pool header of the block of pool 01205 being deallocated. 01206 01207 Return Value: 01208 01209 None. 01210 01211 --*/ 01212 01213 { 01214 PPOOL_HEADER Buddy,Base; 01215 LONG index; 01216 ULONG EntrySize; 01217 01218 // 01219 // Locate buddy of Entry being deallocated. Page size entries have no 01220 // buddy 01221 // 01222 01223 01224 index = Entry->LogAllocationSize - POOL_LOG_MIN; 01225 01226 EntrySize = (1L << Entry->LogAllocationSize); 01227 01228 if ( EntrySize < POOL_PAGE_SIZE ) { 01229 01230 // 01231 // buddy of Entry is LogAllocationSize bytes from Entry rounded 01232 // down on a 2*LogAllocationSize boundry 01233 // 01234 01235 Buddy = (PPOOL_HEADER)((ULONG)Entry ^ EntrySize); 01236 01237 // 01238 // see if buddy is free. If so, then join buddy and Entry and 01239 // deallocate the joined Entry 01240 // 01241 01242 if ( Buddy->LogAllocationSize == 0 && 01243 Buddy->PoolType == index ) { 01244 01245 // 01246 // buddy is free. Figure out which Entry is the base. 01247 // Convert the size of the base to next larger size and 01248 // deallocate the new Entry 01249 // 01250 01251 Base = ((ULONG)Entry & EntrySize) ? Buddy : Entry; 01252 01253 RemoveEntryList((PLIST_ENTRY)((PCH)Buddy + POOL_OVERHEAD)); 01254 01255 // 01256 // Update statistics for buddy's list head. 01257 // 01258 01259 PoolDesc->ListHeads[index].CurrentFreeLength--; 01260 01261 // 01262 // mark base as allocated as next size Entry and then deallocate it 01263 // 01264 01265 Base->LogAllocationSize = Entry->LogAllocationSize + 1; 01266 01267 DeallocatePoolInternal(PoolDesc,Base); 01268 01269 } else { 01270 01271 // 01272 // Buddy is not free, so just mark Entry as free and return to 01273 // appropriate list head 01274 // 01275 01276 #if defined(TRACE_ALLOC) || defined (DEADBEEF) 01277 { 01278 PULONG OldPool; 01279 ULONG LongCount; 01280 01281 OldPool = (PULONG)((PCH)Entry + POOL_OVERHEAD); 01282 LongCount = EntrySize >> 2; 01283 LongCount -= (POOL_OVERHEAD>>2); 01284 01285 while(LongCount--) { 01286 *OldPool++ = 0xBAADF00D; 01287 } 01288 } 01289 #endif //TRACE_ALLOC 01290 01291 InsertTailList( 01292 &PoolDesc->ListHeads[index].ListHead, 01293 (PLIST_ENTRY)((PCH)Entry + POOL_OVERHEAD) 01294 ); 01295 01296 PoolDesc->ListHeads[index].CurrentFreeLength++; 01297 01298 Entry->LogAllocationSize = 0; 01299 Entry->PoolType = index; 01300 } 01301 01302 } else { 01303 01304 // 01305 // Page Sized Entry. Check threshold. If deallocating Entry 01306 // would cross threshold then give back the page. Otherwise put 01307 // it on the free list 01308 // 01309 01310 if ( PoolDesc->ListHeads[index].CurrentFreeLength == PoolDesc->Threshold ) { 01311 01312 MiFreePoolPages (Entry); 01313 01314 } else { 01315 01316 // 01317 // so just mark Entry as free and return to appropriate list head 01318 // 01319 01320 #if defined(TRACE_ALLOC) || defined (DEADBEEF) 01321 { 01322 PULONG OldPool; 01323 ULONG LongCount; 01324 01325 OldPool = (PULONG)((PCH)Entry + POOL_OVERHEAD); 01326 LongCount = EntrySize >> 2; 01327 LongCount -= (POOL_OVERHEAD>>2); 01328 01329 while(LongCount--) { 01330 *OldPool++ = 0xBAADF00D; 01331 } 01332 } 01333 #endif //TRACE_ALLOC 01334 01335 InsertTailList( 01336 &PoolDesc->ListHeads[index].ListHead, 01337 (PLIST_ENTRY)((PCH)Entry + POOL_OVERHEAD) 01338 ); 01339 01340 PoolDesc->ListHeads[index].CurrentFreeLength++; 01341 01342 Entry->LogAllocationSize = 0; 01343 Entry->PoolType = index; 01344 01345 } 01346 } 01347 } 01348 01349 01350 VOID 01351 DumpPool( 01352 IN PSZ s, 01353 IN POOL_TYPE pt 01354 ) 01355 { 01356 PPOOL_DESCRIPTOR pd; 01357 PPOOL_HEADER ph,bph; 01358 PPOOL_LIST_HEAD plh; 01359 PLIST_ENTRY lh,next; 01360 LONG i; 01361 ULONG size; 01362 01363 pd = PoolVector[pt]; 01364 01365 DbgPrint("\n\n%s\n",s); 01366 01367 DbgPrint("PoolType: 0x%lx\n",(ULONG)pd->PoolType); 01368 DbgPrint("TotalPages: 0x%lx\n",pd->TotalPages); 01369 DbgPrint("Threshold: 0x%lx\n",pd->Threshold); 01370 for (i=0; i<POOL_LIST_HEADS; i++ ) { 01371 plh = &pd->ListHeads[i]; 01372 size = (1 << (i + POOL_LOG_MIN)); 01373 DbgPrint("\npd_list_head[0x%lx] size 0x%lx\n",i,size); 01374 DbgPrint("\tCurrentFreeLength 0x%lx\n",plh->CurrentFreeLength); 01375 DbgPrint("\t&ListHead 0x%lx\n",&plh->ListHead); 01376 lh = &plh->ListHead; 01377 DbgPrint("\t\tpFlink 0x%lx\n",lh->Flink); 01378 DbgPrint("\t\tpBlink 0x%lx\n",lh->Blink); 01379 next = lh->Flink; 01380 while ( next != lh ) { 01381 ph = (PPOOL_HEADER)((PCH)next - POOL_OVERHEAD); 01382 DbgPrint("\t\t\tpool header at 0x%lx list 0x%lx\n",ph,next); 01383 DbgPrint("\t\t\tLogAllocationSize 0x%lx 0x%lx\n",(ULONG)ph->LogAllocationSize,(ULONG)(1<<ph->LogAllocationSize)); 01384 DbgPrint("\t\t\tPoolType 0x%lx\n",(ULONG)ph->PoolType); 01385 DbgPrint("\t\t\tProcessBilled 0x%lx\n",ph->ProcessBilled); 01386 if ( size != POOL_PAGE_SIZE ) { 01387 bph = (PPOOL_HEADER)((ULONG)ph ^ size); 01388 DbgPrint("\t\t\t\tBuddy pool header at 0x%lx\n",bph); 01389 DbgPrint("\t\t\t\tBuddy LogAllocationSize 0x%lx 0x%lx\n",(ULONG)bph->LogAllocationSize,(ULONG)(1<<bph->LogAllocationSize)); 01390 DbgPrint("\t\t\t\tBuddy PoolType 0x%lx\n",(ULONG)bph->PoolType); 01391 DbgPrint("\t\t\t\tBuddy ProcessBilled 0x%lx\n",bph->ProcessBilled); 01392 } 01393 next = next->Flink; 01394 } 01395 } 01396 } 01397 01398 01399 VOID 01400 CheckPool() 01401 { 01402 PPOOL_DESCRIPTOR pd; 01403 PPOOL_HEADER ph,bph; 01404 PPOOL_LIST_HEAD plh; 01405 PLIST_ENTRY lh,next,lh2,next2; 01406 BOOLEAN buddyinlist; 01407 LONG i,j; 01408 ULONG size; 01409 01410 pd = PoolVector[NonPagedPool]; 01411 01412 if ( pd->PoolType != NonPagedPool ) { 01413 DbgPrint("pd = %8lx\n", pd); 01414 KeBugCheck(0x70000001); 01415 } 01416 01417 if ( (LONG) pd->TotalPages < 0 ) { 01418 DbgPrint("pd = %8lx\n", pd); 01419 KeBugCheck(0x70000002); 01420 } 01421 01422 for (i=0; i<POOL_LIST_HEADS; i++ ) { 01423 plh = &pd->ListHeads[i]; 01424 size = (1 << (i + POOL_LOG_MIN)); 01425 01426 if ( !IsListEmpty(&plh->ListHead) ) { 01427 01428 lh = &plh->ListHead; 01429 next = lh->Flink; 01430 while ( next != lh ) { 01431 ph = (PPOOL_HEADER)((PCH)next - POOL_OVERHEAD); 01432 01433 if ( MmDeterminePoolType(ph) != NonPagedPool ) { 01434 DbgPrint("ph = %8lx\n", ph); 01435 KeBugCheck(0x70000004); 01436 } 01437 if ( size != POOL_PAGE_SIZE ) { 01438 bph = (PPOOL_HEADER)((ULONG)ph ^ size); 01439 if ( bph->LogAllocationSize == 0 && 01440 bph->PoolType == i ) { 01441 lh2 = &plh->ListHead; 01442 next2 = lh2->Flink; 01443 buddyinlist = FALSE; 01444 while ( next2 != lh2 ) { 01445 ph = (PPOOL_HEADER)((PCH)next - POOL_OVERHEAD); 01446 if ( bph == ph ) { 01447 buddyinlist = TRUE; 01448 } 01449 next2 = next2->Flink; 01450 } 01451 if ( !buddyinlist ) { 01452 KeBugCheck(0x70000005); 01453 } 01454 } 01455 } 01456 if ( next == next->Flink ) { 01457 DbgPrint("next = %8lx\n", next); 01458 KeBugCheck(0x70000006); 01459 } 01460 next = next->Flink; 01461 } 01462 } 01463 01464 } 01465 } 01466 VOID 01467 DumpAllocatedPool( 01468 IN ULONG DumpOrFlush 01469 ) 01470 { 01471 VOID MiFlushUnusedSections( VOID ); 01472 POOL_TYPE pt; 01473 ULONG PoolUsage[MaxPoolType]; 01474 ULONG PoolFree[MaxPoolType]; 01475 01476 PPOOL_DESCRIPTOR pd; 01477 PPOOL_LIST_HEAD plh; 01478 PLIST_ENTRY lh,next; 01479 LONG i,j,k; 01480 ULONG size; 01481 01482 if ( DumpOrFlush ) { 01483 MiFlushUnusedSections(); 01484 return; 01485 } 01486 01487 DbgPrint ("PoolHack does not work with POOL command\n"); 01488 01489 return; 01490 } 01491 01492 VOID 01493 ExQueryPoolUsage( 01494 OUT PULONG PagedPoolPages, 01495 OUT PULONG NonPagedPoolPages 01496 ) 01497 { 01498 PPOOL_DESCRIPTOR pd; 01499 01500 pd = PoolVector[PagedPool]; 01501 *PagedPoolPages = pd->TotalPages; 01502 pd = PoolVector[PagedPoolMustSucceed]; 01503 *PagedPoolPages += pd->TotalPages; 01504 01505 pd = PoolVector[NonPagedPool]; 01506 *NonPagedPoolPages = pd->TotalPages; 01507 pd = PoolVector[NonPagedPoolMustSucceed]; 01508 *NonPagedPoolPages += pd->TotalPages; 01509 01510 }

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