00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
#if DBG
00027
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
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
00085
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
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
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211 {
00212
00213 KIRQL Irql;
00214
00215
if ( PoolType ==
NonPagedPool || PoolType ==
NonPagedPoolMustSucceed ) {
00216
00217
00218
00219
00220
00221
KeAcquireSpinLock((PKSPIN_LOCK)
PoolVector[PoolType]->LockAddress, &Irql);
00222
return Irql;
00223 }
else {
00224
00225
00226
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
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
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 {
00295
00296
if ( PoolType ==
NonPagedPool || (PoolType) ==
NonPagedPoolMustSucceed ) {
00297
00298
00299
00300
00301
00302
KeReleaseSpinLock(
00303 (PKSPIN_LOCK)
PoolVector[PoolType]->LockAddress,
00304 LockHandle
00305 );
00306
00307 }
else {
00308
00309
00310
00311
00312
00313
KeReleaseMutex((
PKMUTEX)
PoolVector[PoolType]->LockAddress,Wait);
00314
00315
00316
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
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
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,1
L,1
L);
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
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
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, 1
L, 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 0xfffffff8
L);
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
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 0
L,
00616 1
L,
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
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
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
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
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
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
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
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
00843
00844
00845
00846
00847
if ( !IsListEmpty(&PoolListHead->
ListHead) ) {
00848
00849
00850
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
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
00880
00881
00882
00883
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
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
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
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
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
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
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
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 0
L,
01140 1
L,
01141
FALSE
01142 );
01143
KeLowerIrql(xIrql);
01144
01145 }
01146
#endif // TRACE_ALLOC
01147
01148
#ifndef TRACE_ALLOC
01149
01150
01151
01152
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
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213 {
01214
PPOOL_HEADER Buddy,Base;
01215 LONG index;
01216 ULONG EntrySize;
01217
01218
01219
01220
01221
01222
01223
01224 index = Entry->
LogAllocationSize -
POOL_LOG_MIN;
01225
01226 EntrySize = (1
L << Entry->LogAllocationSize);
01227
01228
if ( EntrySize <
POOL_PAGE_SIZE ) {
01229
01230
01231
01232
01233
01234
01235 Buddy = (
PPOOL_HEADER)((ULONG)Entry ^ EntrySize);
01236
01237
01238
01239
01240
01241
01242
if ( Buddy->
LogAllocationSize == 0 &&
01243 Buddy->
PoolType == index ) {
01244
01245
01246
01247
01248
01249
01250
01251 Base = ((ULONG)Entry & EntrySize) ? Buddy : Entry;
01252
01253 RemoveEntryList((PLIST_ENTRY)((PCH)Buddy +
POOL_OVERHEAD));
01254
01255
01256
01257
01258
01259 PoolDesc->ListHeads[index].CurrentFreeLength--;
01260
01261
01262
01263
01264
01265 Base->
LogAllocationSize = Entry->LogAllocationSize + 1;
01266
01267
DeallocatePoolInternal(PoolDesc,Base);
01268
01269 }
else {
01270
01271
01272
01273
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
01306
01307
01308
01309
01310
if ( PoolDesc->ListHeads[index].CurrentFreeLength == PoolDesc->Threshold ) {
01311
01312
MiFreePoolPages (Entry);
01313
01314 }
else {
01315
01316
01317
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 }