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
);
38 ExAllocateArmPoolWithTag(POOL_TYPE PoolType
,
43 EiAllocatePool(POOL_TYPE PoolType
,
49 PCHAR TagChars
= (PCHAR
)&Tag
;
52 KeBugCheckEx(BAD_POOL_CALLER
, 0x9b, PoolType
, NumberOfBytes
, (ULONG_PTR
)Caller
);
54 KeBugCheckEx(BAD_POOL_CALLER
, 0x9c, PoolType
, NumberOfBytes
, (ULONG_PTR
)Caller
);
56 #define IS_LETTER_OR_DIGIT(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z') || ((c) >= '0' && (c) <= '9'))
57 if (!IS_LETTER_OR_DIGIT(TagChars
[0]) &&
58 !IS_LETTER_OR_DIGIT(TagChars
[1]) &&
59 !IS_LETTER_OR_DIGIT(TagChars
[2]) &&
60 !IS_LETTER_OR_DIGIT(TagChars
[3]))
61 KeBugCheckEx(BAD_POOL_CALLER
, 0x9d, Tag
, PoolType
, (ULONG_PTR
)Caller
);
63 /* FIXME: Handle SESSION_POOL_MASK, VERIFIER_POOL_MASK, QUOTA_POOL_MASK */
64 if (PoolType
& PAGED_POOL_MASK
)
66 if (KeGetCurrentIrql() > APC_LEVEL
)
67 KeBugCheckEx(BAD_POOL_CALLER
, 0x08, KeGetCurrentIrql(), PoolType
, Tag
);
69 if (ExpIsPoolTagDebuggable(Tag
))
70 Block
= ExpAllocateDebugPool(PoolType
, NumberOfBytes
, Tag
, Caller
, TRUE
);
73 Block
= ExAllocatePagedPoolWithTag(PoolType
, NumberOfBytes
, Tag
);
77 if (KeGetCurrentIrql() > DISPATCH_LEVEL
)
78 KeBugCheckEx(BAD_POOL_CALLER
, 0x08, KeGetCurrentIrql(), PoolType
, Tag
);
80 if (ExpIsPoolTagDebuggable(Tag
))
81 Block
= ExpAllocateDebugPool(PoolType
, NumberOfBytes
, Tag
, Caller
, TRUE
);
84 Block
= ExAllocateArmPoolWithTag(PoolType
, NumberOfBytes
, Tag
);
87 if ((PoolType
& MUST_SUCCEED_POOL_MASK
) && !Block
)
88 KeBugCheckEx(BAD_POOL_CALLER
, 0x9a, PoolType
, NumberOfBytes
, Tag
);
96 ExAllocatePool (POOL_TYPE PoolType
, SIZE_T NumberOfBytes
)
98 * FUNCTION: Allocates pool memory of a specified type and returns a pointer
99 * to the allocated block. This routine is used for general purpose allocation
103 * Specifies the type of memory to allocate which can be one
107 * NonPagedPoolMustSucceed
108 * NonPagedPoolCacheAligned
109 * NonPagedPoolCacheAlignedMustS
111 * PagedPoolCacheAligned
114 * Specifies the number of bytes to allocate
115 * RETURNS: The allocated block on success
121 #if defined(__GNUC__)
123 Block
= EiAllocatePool(PoolType
,
126 (PVOID
)__builtin_return_address(0));
127 #elif defined(_MSC_VER)
129 Block
= EiAllocatePool(PoolType
,
134 #error Unknown compiler
145 ExAllocatePoolWithTag (POOL_TYPE PoolType
, SIZE_T NumberOfBytes
, ULONG Tag
)
149 #if defined(__GNUC__)
151 Block
= EiAllocatePool(PoolType
,
154 (PVOID
)__builtin_return_address(0));
155 #elif defined(_MSC_VER)
157 Block
= EiAllocatePool(PoolType
,
160 &ExAllocatePoolWithTag
);
162 #error Unknown compiler
172 #undef ExAllocatePoolWithQuota
173 #undef ExAllocatePoolWithQuotaTag
175 ExAllocatePoolWithQuota (POOL_TYPE PoolType
, SIZE_T NumberOfBytes
)
177 return(ExAllocatePoolWithQuotaTag(PoolType
, NumberOfBytes
, TAG_NONE
));
185 ExAllocatePoolWithTagPriority(
186 IN POOL_TYPE PoolType
,
187 IN SIZE_T NumberOfBytes
,
189 IN EX_POOL_PRIORITY Priority
192 /* Do the allocation */
194 return ExAllocatePoolWithTag(PoolType
, NumberOfBytes
, Tag
);
202 ExAllocatePoolWithQuotaTag (IN POOL_TYPE PoolType
,
203 IN SIZE_T NumberOfBytes
,
209 /* Allocate the Pool First */
210 Block
= EiAllocatePool(PoolType
,
213 &ExAllocatePoolWithQuotaTag
);
215 /* "Quota is not charged to the thread for allocations >= PAGE_SIZE" - OSR Docs */
216 if (!(NumberOfBytes
>= PAGE_SIZE
))
218 /* Get the Current Process */
219 Process
= PsGetCurrentProcess();
221 /* PsChargePoolQuota returns an exception, so this needs SEH */
224 /* FIXME: Is there a way to get the actual Pool size allocated from the pool header? */
225 PsChargePoolQuota(Process
,
226 PoolType
& PAGED_POOL_MASK
,
229 _SEH2_EXCEPT((ExFreePool(Block
), EXCEPTION_CONTINUE_SEARCH
))
231 /* Quota Exceeded and the caller had no SEH! */
232 KeBugCheck(STATUS_QUOTA_EXCEEDED
);
237 /* Return the allocated block */
246 ExFreePool(IN PVOID Block
)
248 ExFreePoolWithTag(Block
, 0);
253 ExFreeArmPoolWithTag(PVOID P
,
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
);
294 else if (Block
) ExFreeArmPoolWithTag(Block
, Tag
);
297 /* Warn only for NULL pointers */
300 DPRINT1("Warning: Trying to free a NULL pointer!\n");
304 /* Block was not inside any pool! */
305 KeBugCheckEx(BAD_POOL_CALLER
, 0x42, (ULONG_PTR
)Block
, 0, 0);
314 ExQueryPoolBlockSize (
316 OUT PBOOLEAN QuotaCharged
328 MmAllocateMappingAddress (
329 IN SIZE_T NumberOfBytes
,
343 MmFreeMappingAddress (
344 IN PVOID BaseAddress
,
354 IN POOL_TYPE PoolType
,
355 IN ULONG CurrentMaxQuota
,
356 OUT PULONG NewMaxQuota
359 /* Different quota raises depending on the type (64K vs 512K) */
360 if (PoolType
== PagedPool
) {
362 /* Make sure that 4MB is still left */
363 if ((MM_PAGED_POOL_SIZE
>> 12) < ((MmPagedPoolSize
+ 4194304) >> 12)) {
367 /* Increase Paged Pool Quota by 512K */
368 MmTotalPagedPoolQuota
+= 524288;
369 *NewMaxQuota
= CurrentMaxQuota
+ 524288;
372 } else { /* Nonpaged Pool */
374 /* Check if we still have 200 pages free*/
375 if (MmStats
.NrFreePages
< 200) return FALSE
;
377 *NewMaxQuota
= CurrentMaxQuota
+ 65536;