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. Don't forget to increase
18 max pool sizes (MM_[NON]PAGED_POOL_SIZE) in include/internal/mm.h */
22 extern PVOID MiNonPagedPoolStart
;
23 extern ULONG MiNonPagedPoolLength
;
24 extern ULONG MmTotalPagedPoolQuota
;
25 extern ULONG MmTotalNonPagedPoolQuota
;
26 extern MM_STATS MmStats
;
28 /* FUNCTIONS ***************************************************************/
31 EiGetPagedPoolTag(IN PVOID Block
);
34 EiGetNonPagedPoolTag(IN PVOID Block
);
37 EiAllocatePool(POOL_TYPE PoolType
,
43 PCHAR TagChars
= (PCHAR
)&Tag
;
46 KeBugCheckEx(BAD_POOL_CALLER
, 0x9b, PoolType
, NumberOfBytes
, (ULONG_PTR
)Caller
);
47 if (Tag
== TAG('B','I','G',0))
48 KeBugCheckEx(BAD_POOL_CALLER
, 0x9c, PoolType
, NumberOfBytes
, (ULONG_PTR
)Caller
);
50 #define IS_LETTER_OR_DIGIT(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z') || ((c) >= '0' && (c) <= '9'))
51 if (!IS_LETTER_OR_DIGIT(TagChars
[0]) &&
52 !IS_LETTER_OR_DIGIT(TagChars
[1]) &&
53 !IS_LETTER_OR_DIGIT(TagChars
[2]) &&
54 !IS_LETTER_OR_DIGIT(TagChars
[3]))
55 KeBugCheckEx(BAD_POOL_CALLER
, 0x9d, Tag
, PoolType
, (ULONG_PTR
)Caller
);
57 /* FIXME: Handle SESSION_POOL_MASK, VERIFIER_POOL_MASK, QUOTA_POOL_MASK */
58 if (PoolType
& PAGED_POOL_MASK
)
60 if (KeGetCurrentIrql() > APC_LEVEL
)
61 KeBugCheckEx(BAD_POOL_CALLER
, 0x08, KeGetCurrentIrql(), PoolType
, Tag
);
63 if (ExpIsPoolTagDebuggable(Tag
))
64 Block
= ExpAllocateDebugPool(PoolType
, NumberOfBytes
, Tag
, Caller
, TRUE
);
67 Block
= ExAllocatePagedPoolWithTag(PoolType
, NumberOfBytes
, Tag
);
71 if (KeGetCurrentIrql() > DISPATCH_LEVEL
)
72 KeBugCheckEx(BAD_POOL_CALLER
, 0x08, KeGetCurrentIrql(), PoolType
, Tag
);
74 if (ExpIsPoolTagDebuggable(Tag
))
75 Block
= ExpAllocateDebugPool(PoolType
, NumberOfBytes
, Tag
, Caller
, TRUE
);
78 Block
= ExAllocateNonPagedPoolWithTag(PoolType
, NumberOfBytes
, Tag
, Caller
);
81 if ((PoolType
& MUST_SUCCEED_POOL_MASK
) && !Block
)
82 KeBugCheckEx(BAD_POOL_CALLER
, 0x9a, PoolType
, NumberOfBytes
, Tag
);
90 ExAllocatePool (POOL_TYPE PoolType
, SIZE_T NumberOfBytes
)
92 * FUNCTION: Allocates pool memory of a specified type and returns a pointer
93 * to the allocated block. This routine is used for general purpose allocation
97 * Specifies the type of memory to allocate which can be one
101 * NonPagedPoolMustSucceed
102 * NonPagedPoolCacheAligned
103 * NonPagedPoolCacheAlignedMustS
105 * PagedPoolCacheAligned
108 * Specifies the number of bytes to allocate
109 * RETURNS: The allocated block on success
115 #if defined(__GNUC__)
117 Block
= EiAllocatePool(PoolType
,
120 (PVOID
)__builtin_return_address(0));
121 #elif defined(_MSC_VER)
123 Block
= EiAllocatePool(PoolType
,
128 #error Unknown compiler
139 ExAllocatePoolWithTag (POOL_TYPE PoolType
, SIZE_T NumberOfBytes
, ULONG Tag
)
143 #if defined(__GNUC__)
145 Block
= EiAllocatePool(PoolType
,
148 (PVOID
)__builtin_return_address(0));
149 #elif defined(_MSC_VER)
151 Block
= EiAllocatePool(PoolType
,
154 &ExAllocatePoolWithTag
);
156 #error Unknown compiler
166 #undef ExAllocatePoolWithQuota
168 ExAllocatePoolWithQuota (POOL_TYPE PoolType
, SIZE_T NumberOfBytes
)
170 return(ExAllocatePoolWithQuotaTag(PoolType
, NumberOfBytes
, TAG_NONE
));
178 ExAllocatePoolWithTagPriority(
179 IN POOL_TYPE PoolType
,
180 IN SIZE_T NumberOfBytes
,
182 IN EX_POOL_PRIORITY Priority
185 /* Check if this is one of the "Special" Flags, used by the Verifier */
187 /* Check if this is a xxSpecialUnderrun */
189 return MiAllocateSpecialPool(PoolType
, NumberOfBytes
, Tag
, 1);
190 } else { /* xxSpecialOverrun */
191 return MiAllocateSpecialPool(PoolType
, NumberOfBytes
, Tag
, 0);
195 /* FIXME: Do Ressource Checking Based on Priority and fail if resources too low*/
197 /* Do the allocation */
198 return ExAllocatePoolWithTag(PoolType
, NumberOfBytes
, Tag
);
204 #undef ExAllocatePoolWithQuotaTag
207 ExAllocatePoolWithQuotaTag (IN POOL_TYPE PoolType
,
208 IN SIZE_T NumberOfBytes
,
214 /* Allocate the Pool First */
215 Block
= EiAllocatePool(PoolType
,
218 &ExAllocatePoolWithQuotaTag
);
220 /* "Quota is not charged to the thread for allocations >= PAGE_SIZE" - OSR Docs */
221 if (!(NumberOfBytes
>= PAGE_SIZE
))
223 /* Get the Current Process */
224 Process
= PsGetCurrentProcess();
226 /* PsChargePoolQuota returns an exception, so this needs SEH */
229 /* FIXME: Is there a way to get the actual Pool size allocated from the pool header? */
230 PsChargePoolQuota(Process
,
231 PoolType
& PAGED_POOL_MASK
,
234 _SEH2_EXCEPT((ExFreePool(Block
), EXCEPTION_CONTINUE_SEARCH
))
236 /* Quota Exceeded and the caller had no SEH! */
237 KeBugCheck(STATUS_QUOTA_EXCEEDED
);
242 /* Return the allocated block */
251 ExFreePool(IN PVOID Block
)
253 ExFreePoolWithTag(Block
, 0);
265 /* Check for paged pool */
266 if (Block
>= MmPagedPoolBase
&&
267 (char*)Block
< ((char*)MmPagedPoolBase
+ MmPagedPoolSize
))
271 if (Tag
!= 0 && Tag
!= EiGetPagedPoolTag(Block
))
272 KeBugCheckEx(BAD_POOL_CALLER
,
275 EiGetPagedPoolTag(Block
),
279 if (KeGetCurrentIrql() > APC_LEVEL
)
280 KeBugCheckEx(BAD_POOL_CALLER
,
286 /* Free from paged pool */
288 if (ExpIsPoolTagDebuggable(Tag
))
289 ExpFreeDebugPool(Block
, TRUE
);
292 ExFreePagedPool(Block
);
295 /* Check for non-paged pool */
296 else if (Block
>= MiNonPagedPoolStart
&&
297 (char*)Block
< ((char*)MiNonPagedPoolStart
+ MiNonPagedPoolLength
))
301 if (Tag
!= 0 && Tag
!= EiGetNonPagedPoolTag(Block
))
302 KeBugCheckEx(BAD_POOL_CALLER
,
305 EiGetNonPagedPoolTag(Block
),
309 if (KeGetCurrentIrql() > DISPATCH_LEVEL
)
310 KeBugCheckEx(BAD_POOL_CALLER
,
316 /* Free from non-paged pool */
318 if (ExpIsPoolTagDebuggable(Tag
))
319 ExpFreeDebugPool(Block
, FALSE
);
322 ExFreeNonPagedPool(Block
);
326 /* Warn only for NULL pointers */
329 DPRINT1("Warning: Trying to free a NULL pointer!\n");
333 /* Block was not inside any pool! */
334 KeBugCheckEx(BAD_POOL_CALLER
, 0x42, (ULONG_PTR
)Block
, 0, 0);
343 ExQueryPoolBlockSize (
345 OUT PBOOLEAN QuotaCharged
357 MmAllocateMappingAddress (
358 IN SIZE_T NumberOfBytes
,
372 MmFreeMappingAddress (
373 IN PVOID BaseAddress
,
383 IN POOL_TYPE PoolType
,
384 IN ULONG CurrentMaxQuota
,
385 OUT PULONG NewMaxQuota
388 /* Different quota raises depending on the type (64K vs 512K) */
389 if (PoolType
== PagedPool
) {
391 /* Make sure that 4MB is still left */
392 if ((MM_PAGED_POOL_SIZE
>> 12) < ((MmPagedPoolSize
+ 4194304) >> 12)) {
396 /* Increase Paged Pool Quota by 512K */
397 MmTotalPagedPoolQuota
+= 524288;
398 *NewMaxQuota
= CurrentMaxQuota
+ 524288;
401 } else { /* Nonpaged Pool */
403 /* Check if we still have 200 pages free*/
404 if (MmStats
.NrFreePages
< 200) return FALSE
;
406 /* Check that 4MB is still left */
407 if ((MM_NONPAGED_POOL_SIZE
>> 12) < ((MiNonPagedPoolLength
+ 4194304) >> 12)) {
411 /* Increase Non Paged Pool Quota by 64K */
412 MmTotalNonPagedPoolQuota
+= 65536;
413 *NewMaxQuota
= CurrentMaxQuota
+ 65536;