2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/mm/pool.c
5 * PURPOSE: Implements the kernel memory pool
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
10 /* INCLUDES ****************************************************************/
17 /* Uncomment to enable pool overruns debugging */
21 extern PVOID MiNonPagedPoolStart
;
22 extern ULONG MiNonPagedPoolLength
;
23 extern ULONG MmTotalPagedPoolQuota
;
24 extern ULONG MmTotalNonPagedPoolQuota
;
25 extern MM_STATS MmStats
;
27 /* FUNCTIONS ***************************************************************/
30 EiGetPagedPoolTag(IN PVOID Block
);
33 EiGetNonPagedPoolTag(IN PVOID Block
);
36 EiAllocatePool(POOL_TYPE PoolType
,
42 PCHAR TagChars
= (PCHAR
)&Tag
;
45 KeBugCheckEx(BAD_POOL_CALLER
, 0x9b, PoolType
, NumberOfBytes
, (ULONG_PTR
)Caller
);
46 if (Tag
== TAG('B','I','G',0))
47 KeBugCheckEx(BAD_POOL_CALLER
, 0x9c, PoolType
, NumberOfBytes
, (ULONG_PTR
)Caller
);
49 #define IS_LETTER_OR_DIGIT(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z') || ((c) >= '0' && (c) <= '9'))
50 if (!IS_LETTER_OR_DIGIT(TagChars
[0]) &&
51 !IS_LETTER_OR_DIGIT(TagChars
[1]) &&
52 !IS_LETTER_OR_DIGIT(TagChars
[2]) &&
53 !IS_LETTER_OR_DIGIT(TagChars
[3]))
54 KeBugCheckEx(BAD_POOL_CALLER
, 0x9d, Tag
, PoolType
, (ULONG_PTR
)Caller
);
56 /* FIXME: Handle SESSION_POOL_MASK, VERIFIER_POOL_MASK, QUOTA_POOL_MASK */
57 if (PoolType
& PAGED_POOL_MASK
)
59 if (KeGetCurrentIrql() > APC_LEVEL
)
60 KeBugCheckEx(BAD_POOL_CALLER
, 0x08, KeGetCurrentIrql(), PoolType
, Tag
);
61 Block
= ExAllocatePagedPoolWithTag(PoolType
, NumberOfBytes
, Tag
);
65 if (KeGetCurrentIrql() > DISPATCH_LEVEL
)
66 KeBugCheckEx(BAD_POOL_CALLER
, 0x08, KeGetCurrentIrql(), PoolType
, Tag
);
68 if (ExpIsPoolTagDebuggable(Tag
))
69 Block
= ExpAllocateDebugPool(PoolType
, NumberOfBytes
, Tag
, Caller
, TRUE
);
72 Block
= ExAllocateNonPagedPoolWithTag(PoolType
, NumberOfBytes
, Tag
, Caller
);
75 if ((PoolType
& MUST_SUCCEED_POOL_MASK
) && !Block
)
76 KeBugCheckEx(BAD_POOL_CALLER
, 0x9a, PoolType
, NumberOfBytes
, Tag
);
84 ExAllocatePool (POOL_TYPE PoolType
, ULONG NumberOfBytes
)
86 * FUNCTION: Allocates pool memory of a specified type and returns a pointer
87 * to the allocated block. This routine is used for general purpose allocation
91 * Specifies the type of memory to allocate which can be one
95 * NonPagedPoolMustSucceed
96 * NonPagedPoolCacheAligned
97 * NonPagedPoolCacheAlignedMustS
99 * PagedPoolCacheAligned
102 * Specifies the number of bytes to allocate
103 * RETURNS: The allocated block on success
109 #if defined(__GNUC__)
111 Block
= EiAllocatePool(PoolType
,
114 (PVOID
)__builtin_return_address(0));
115 #elif defined(_MSC_VER)
117 Block
= EiAllocatePool(PoolType
,
122 #error Unknown compiler
133 ExAllocatePoolWithTag (POOL_TYPE PoolType
, ULONG NumberOfBytes
, ULONG Tag
)
137 #if defined(__GNUC__)
139 Block
= EiAllocatePool(PoolType
,
142 (PVOID
)__builtin_return_address(0));
143 #elif defined(_MSC_VER)
145 Block
= EiAllocatePool(PoolType
,
148 &ExAllocatePoolWithTag
);
150 #error Unknown compiler
160 #undef ExAllocatePoolWithQuota
162 ExAllocatePoolWithQuota (POOL_TYPE PoolType
, ULONG NumberOfBytes
)
164 return(ExAllocatePoolWithQuotaTag(PoolType
, NumberOfBytes
, TAG_NONE
));
172 ExAllocatePoolWithTagPriority(
173 IN POOL_TYPE PoolType
,
174 IN SIZE_T NumberOfBytes
,
176 IN EX_POOL_PRIORITY Priority
179 /* Check if this is one of the "Special" Flags, used by the Verifier */
181 /* Check if this is a xxSpecialUnderrun */
183 return MiAllocateSpecialPool(PoolType
, NumberOfBytes
, Tag
, 1);
184 } else { /* xxSpecialOverrun */
185 return MiAllocateSpecialPool(PoolType
, NumberOfBytes
, Tag
, 0);
189 /* FIXME: Do Ressource Checking Based on Priority and fail if resources too low*/
191 /* Do the allocation */
192 return ExAllocatePoolWithTag(PoolType
, NumberOfBytes
, Tag
);
198 #undef ExAllocatePoolWithQuotaTag
201 ExAllocatePoolWithQuotaTag (IN POOL_TYPE PoolType
,
202 IN ULONG NumberOfBytes
,
208 /* Allocate the Pool First */
209 Block
= EiAllocatePool(PoolType
,
212 &ExAllocatePoolWithQuotaTag
);
214 /* "Quota is not charged to the thread for allocations >= PAGE_SIZE" - OSR Docs */
215 if (!(NumberOfBytes
>= PAGE_SIZE
))
217 /* Get the Current Process */
218 Process
= PsGetCurrentProcess();
220 /* PsChargePoolQuota returns an exception, so this needs SEH */
223 /* FIXME: Is there a way to get the actual Pool size allocated from the pool header? */
224 PsChargePoolQuota(Process
,
225 PoolType
& PAGED_POOL_MASK
,
228 _SEH2_EXCEPT((ExFreePool(Block
), EXCEPTION_CONTINUE_SEARCH
))
230 /* Quota Exceeded and the caller had no SEH! */
231 KeBugCheck(STATUS_QUOTA_EXCEEDED
);
236 /* Return the allocated block */
245 ExFreePool(IN PVOID Block
)
247 ExFreePoolWithTag(Block
, 0);
259 /* Check for paged pool */
260 if (Block
>= MmPagedPoolBase
&&
261 (char*)Block
< ((char*)MmPagedPoolBase
+ MmPagedPoolSize
))
264 if (Tag
!= 0 && Tag
!= EiGetPagedPoolTag(Block
))
265 KeBugCheckEx(BAD_POOL_CALLER
,
268 EiGetPagedPoolTag(Block
),
272 if (KeGetCurrentIrql() > APC_LEVEL
)
273 KeBugCheckEx(BAD_POOL_CALLER
,
279 /* Free from paged pool */
280 ExFreePagedPool(Block
);
283 /* Check for non-paged pool */
284 else if (Block
>= MiNonPagedPoolStart
&&
285 (char*)Block
< ((char*)MiNonPagedPoolStart
+ MiNonPagedPoolLength
))
288 if (Tag
!= 0 && Tag
!= EiGetNonPagedPoolTag(Block
))
289 KeBugCheckEx(BAD_POOL_CALLER
,
292 EiGetNonPagedPoolTag(Block
),
296 if (KeGetCurrentIrql() > DISPATCH_LEVEL
)
297 KeBugCheckEx(BAD_POOL_CALLER
,
303 /* Free from non-paged pool */
305 if (ExpIsPoolTagDebuggable(Tag
))
306 ExpFreeDebugPool(Block
);
309 ExFreeNonPagedPool(Block
);
313 /* Warn only for NULL pointers */
316 DPRINT1("Warning: Trying to free a NULL pointer!\n");
320 /* Block was not inside any pool! */
321 KeBugCheckEx(BAD_POOL_CALLER
, 0x42, (ULONG_PTR
)Block
, 0, 0);
330 ExQueryPoolBlockSize (
332 OUT PBOOLEAN QuotaCharged
344 MmAllocateMappingAddress (
345 IN SIZE_T NumberOfBytes
,
359 MmFreeMappingAddress (
360 IN PVOID BaseAddress
,
370 IN POOL_TYPE PoolType
,
371 IN ULONG CurrentMaxQuota
,
372 OUT PULONG NewMaxQuota
375 /* Different quota raises depending on the type (64K vs 512K) */
376 if (PoolType
== PagedPool
) {
378 /* Make sure that 4MB is still left */
379 if ((MM_PAGED_POOL_SIZE
>> 12) < ((MmPagedPoolSize
+ 4194304) >> 12)) {
383 /* Increase Paged Pool Quota by 512K */
384 MmTotalPagedPoolQuota
+= 524288;
385 *NewMaxQuota
= CurrentMaxQuota
+ 524288;
388 } else { /* Nonpaged Pool */
390 /* Check if we still have 200 pages free*/
391 if (MmStats
.NrFreePages
< 200) return FALSE
;
393 /* Check that 4MB is still left */
394 if ((MM_NONPAGED_POOL_SIZE
>> 12) < ((MiNonPagedPoolLength
+ 4194304) >> 12)) {
398 /* Increase Non Paged Pool Quota by 64K */
399 MmTotalNonPagedPoolQuota
+= 65536;
400 *NewMaxQuota
= CurrentMaxQuota
+ 65536;