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 extern ULONG MiNonPagedPoolLength
;
18 extern ULONG MmTotalPagedPoolQuota
;
19 extern ULONG MmTotalNonPagedPoolQuota
;
20 extern MM_STATS MmStats
;
22 /* FUNCTIONS ***************************************************************/
25 EiGetPagedPoolTag(IN PVOID Block
);
28 EiGetNonPagedPoolTag(IN PVOID Block
);
31 EiAllocatePool(POOL_TYPE PoolType
,
37 PCHAR TagChars
= (PCHAR
)&Tag
;
40 KeBugCheckEx(BAD_POOL_CALLER
, 0x9b, PoolType
, NumberOfBytes
, (ULONG_PTR
)Caller
);
41 if (Tag
== TAG('B','I','G',0))
42 KeBugCheckEx(BAD_POOL_CALLER
, 0x9c, PoolType
, NumberOfBytes
, (ULONG_PTR
)Caller
);
44 #define IS_LETTER_OR_DIGIT(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z') || ((c) >= '0' && (c) <= '9'))
45 if (!IS_LETTER_OR_DIGIT(TagChars
[0]) &&
46 !IS_LETTER_OR_DIGIT(TagChars
[1]) &&
47 !IS_LETTER_OR_DIGIT(TagChars
[2]) &&
48 !IS_LETTER_OR_DIGIT(TagChars
[3]))
49 KeBugCheckEx(BAD_POOL_CALLER
, 0x9d, Tag
, PoolType
, (ULONG_PTR
)Caller
);
51 /* FIXME: Handle SESSION_POOL_MASK, VERIFIER_POOL_MASK, QUOTA_POOL_MASK */
52 if (PoolType
& PAGED_POOL_MASK
)
54 if (KeGetCurrentIrql() > APC_LEVEL
)
55 KeBugCheckEx(BAD_POOL_CALLER
, 0x08, KeGetCurrentIrql(), PoolType
, Tag
);
56 Block
= ExAllocatePagedPoolWithTag(PoolType
, NumberOfBytes
, Tag
);
60 if (KeGetCurrentIrql() > DISPATCH_LEVEL
)
61 KeBugCheckEx(BAD_POOL_CALLER
, 0x08, KeGetCurrentIrql(), PoolType
, Tag
);
62 Block
= ExAllocateNonPagedPoolWithTag(PoolType
, NumberOfBytes
, Tag
, Caller
);
65 if ((PoolType
& MUST_SUCCEED_POOL_MASK
) && !Block
)
66 KeBugCheckEx(BAD_POOL_CALLER
, 0x9a, PoolType
, NumberOfBytes
, Tag
);
74 ExAllocatePool (POOL_TYPE PoolType
, SIZE_T NumberOfBytes
)
76 * FUNCTION: Allocates pool memory of a specified type and returns a pointer
77 * to the allocated block. This routine is used for general purpose allocation
81 * Specifies the type of memory to allocate which can be one
85 * NonPagedPoolMustSucceed
86 * NonPagedPoolCacheAligned
87 * NonPagedPoolCacheAlignedMustS
89 * PagedPoolCacheAligned
92 * Specifies the number of bytes to allocate
93 * RETURNS: The allocated block on success
101 Block
= EiAllocatePool(PoolType
,
104 (PVOID
)__builtin_return_address(0));
105 #elif defined(_MSC_VER)
107 Block
= EiAllocatePool(PoolType
,
112 #error Unknown compiler
123 ExAllocatePoolWithTag (POOL_TYPE PoolType
, SIZE_T NumberOfBytes
, ULONG Tag
)
127 #if defined(__GNUC__)
129 Block
= EiAllocatePool(PoolType
,
132 (PVOID
)__builtin_return_address(0));
133 #elif defined(_MSC_VER)
135 Block
= EiAllocatePool(PoolType
,
138 &ExAllocatePoolWithTag
);
140 #error Unknown compiler
151 ExAllocatePoolWithQuota (POOL_TYPE PoolType
, SIZE_T NumberOfBytes
)
153 return(ExAllocatePoolWithQuotaTag(PoolType
, NumberOfBytes
, TAG_NONE
));
161 ExAllocatePoolWithTagPriority(
162 IN POOL_TYPE PoolType
,
163 IN SIZE_T NumberOfBytes
,
165 IN EX_POOL_PRIORITY Priority
168 /* Check if this is one of the "Special" Flags, used by the Verifier */
170 /* Check if this is a xxSpecialUnderrun */
172 return MiAllocateSpecialPool(PoolType
, NumberOfBytes
, Tag
, 1);
173 } else { /* xxSpecialOverrun */
174 return MiAllocateSpecialPool(PoolType
, NumberOfBytes
, Tag
, 0);
178 /* FIXME: Do Ressource Checking Based on Priority and fail if resources too low*/
180 /* Do the allocation */
181 return ExAllocatePoolWithTag(PoolType
, NumberOfBytes
, Tag
);
184 _SEH_DEFINE_LOCALS(ExQuotaPoolVars
)
189 _SEH_FILTER(FreeAndGoOn
)
191 _SEH_ACCESS_LOCALS(ExQuotaPoolVars
);
193 /* Couldn't charge, so free the pool and let the caller SEH manage */
194 ExFreePool(_SEH_VAR(Block
));
195 return EXCEPTION_CONTINUE_SEARCH
;
203 ExAllocatePoolWithQuotaTag (IN POOL_TYPE PoolType
,
204 IN SIZE_T NumberOfBytes
,
208 _SEH_DECLARE_LOCALS(ExQuotaPoolVars
);
210 /* Allocate the Pool First */
211 _SEH_VAR(Block
) = EiAllocatePool(PoolType
,
214 &ExAllocatePoolWithQuotaTag
);
216 /* "Quota is not charged to the thread for allocations >= PAGE_SIZE" - OSR Docs */
217 if (!(NumberOfBytes
>= PAGE_SIZE
))
219 /* Get the Current Process */
220 Process
= PsGetCurrentProcess();
222 /* PsChargePoolQuota returns an exception, so this needs SEH */
225 /* FIXME: Is there a way to get the actual Pool size allocated from the pool header? */
226 PsChargePoolQuota(Process
,
227 PoolType
& PAGED_POOL_MASK
,
230 _SEH_EXCEPT(FreeAndGoOn
)
232 /* Quota Exceeded and the caller had no SEH! */
233 KeBugCheck(STATUS_QUOTA_EXCEEDED
);
238 /* Return the allocated block */
239 return _SEH_VAR(Block
);
247 ExFreePool(IN PVOID Block
)
249 if (Block
>= MmPagedPoolBase
&& (char*)Block
< ((char*)MmPagedPoolBase
+ MmPagedPoolSize
))
251 if (KeGetCurrentIrql() > APC_LEVEL
)
252 KeBugCheckEx(BAD_POOL_CALLER
, 0x09, KeGetCurrentIrql(), PagedPool
, (ULONG_PTR
)Block
);
253 ExFreePagedPool(Block
);
257 if (KeGetCurrentIrql() > DISPATCH_LEVEL
)
258 KeBugCheckEx(BAD_POOL_CALLER
, 0x09, KeGetCurrentIrql(), NonPagedPool
, (ULONG_PTR
)Block
);
259 ExFreeNonPagedPool(Block
);
267 ExFreePoolWithTag(IN PVOID Block
, IN ULONG Tag
)
271 if (Block
>= MmPagedPoolBase
&& (char*)Block
< ((char*)MmPagedPoolBase
+ MmPagedPoolSize
))
272 BlockTag
= EiGetPagedPoolTag(Block
);
274 BlockTag
= EiGetNonPagedPoolTag(Block
);
277 KeBugCheckEx(BAD_POOL_CALLER
, 0x0a, (ULONG_PTR
)Block
, BlockTag
, Tag
);
287 ExQueryPoolBlockSize (
289 OUT PBOOLEAN QuotaCharged
301 MmAllocateMappingAddress (
302 IN SIZE_T NumberOfBytes
,
316 MmFreeMappingAddress (
317 IN PVOID BaseAddress
,
327 IN POOL_TYPE PoolType
,
328 IN ULONG CurrentMaxQuota
,
329 OUT PULONG NewMaxQuota
332 /* Different quota raises depending on the type (64K vs 512K) */
333 if (PoolType
== PagedPool
) {
335 /* Make sure that 4MB is still left */
336 if ((MM_PAGED_POOL_SIZE
>> 12) < ((MmPagedPoolSize
+ 4194304) >> 12)) {
340 /* Increase Paged Pool Quota by 512K */
341 MmTotalPagedPoolQuota
+= 524288;
342 *NewMaxQuota
= CurrentMaxQuota
+ 524288;
345 } else { /* Nonpaged Pool */
347 /* Check if we still have 200 pages free*/
348 if (MmStats
.NrFreePages
< 200) return FALSE
;
350 /* Check that 4MB is still left */
351 if ((MM_NONPAGED_POOL_SIZE
>> 12) < ((MiNonPagedPoolLength
+ 4194304) >> 12)) {
355 /* Increase Non Paged Pool Quota by 64K */
356 MmTotalNonPagedPoolQuota
+= 65536;
357 *NewMaxQuota
= CurrentMaxQuota
+ 65536;