dd75a47dd524d2bfa33c5728de806280fa1ece31
[reactos.git] / reactos / ntoskrnl / mm / pool.c
1 /*
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
6 *
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
8 */
9
10 /* INCLUDES ****************************************************************/
11
12 #include <ntoskrnl.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
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 */
19 //#define DEBUG_NPOOL
20 //#define DEBUG_PPOOL
21
22 extern PVOID MiNonPagedPoolStart;
23 extern ULONG MiNonPagedPoolLength;
24 extern ULONG MmTotalPagedPoolQuota;
25 extern ULONG MmTotalNonPagedPoolQuota;
26 extern MM_STATS MmStats;
27
28 /* FUNCTIONS ***************************************************************/
29
30 ULONG NTAPI
31 EiGetPagedPoolTag(IN PVOID Block);
32
33 ULONG NTAPI
34 EiGetNonPagedPoolTag(IN PVOID Block);
35
36 PVOID
37 NTAPI
38 ExAllocateArmPoolWithTag(POOL_TYPE PoolType,
39 SIZE_T NumberOfBytes,
40 ULONG Tag);
41
42 static PVOID NTAPI
43 EiAllocatePool(POOL_TYPE PoolType,
44 ULONG NumberOfBytes,
45 ULONG Tag,
46 PVOID Caller)
47 {
48 PVOID Block;
49 PCHAR TagChars = (PCHAR)&Tag;
50
51 if (Tag == 0)
52 KeBugCheckEx(BAD_POOL_CALLER, 0x9b, PoolType, NumberOfBytes, (ULONG_PTR)Caller);
53 if (Tag == TAG('B','I','G',0))
54 KeBugCheckEx(BAD_POOL_CALLER, 0x9c, PoolType, NumberOfBytes, (ULONG_PTR)Caller);
55
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);
62
63 /* FIXME: Handle SESSION_POOL_MASK, VERIFIER_POOL_MASK, QUOTA_POOL_MASK */
64 if (PoolType & PAGED_POOL_MASK)
65 {
66 if (KeGetCurrentIrql() > APC_LEVEL)
67 KeBugCheckEx(BAD_POOL_CALLER, 0x08, KeGetCurrentIrql(), PoolType, Tag);
68 #ifdef DEBUG_PPOOL
69 if (ExpIsPoolTagDebuggable(Tag))
70 Block = ExpAllocateDebugPool(PoolType, NumberOfBytes, Tag, Caller, TRUE);
71 else
72 #endif
73 Block = ExAllocatePagedPoolWithTag(PoolType, NumberOfBytes, Tag);
74 }
75 else
76 {
77 if (KeGetCurrentIrql() > DISPATCH_LEVEL)
78 KeBugCheckEx(BAD_POOL_CALLER, 0x08, KeGetCurrentIrql(), PoolType, Tag);
79 #ifdef DEBUG_NPOOL
80 if (ExpIsPoolTagDebuggable(Tag))
81 Block = ExpAllocateDebugPool(PoolType, NumberOfBytes, Tag, Caller, TRUE);
82 else
83 #endif
84 Block = ExAllocateArmPoolWithTag(PoolType, NumberOfBytes, Tag);
85 }
86
87 if ((PoolType & MUST_SUCCEED_POOL_MASK) && !Block)
88 KeBugCheckEx(BAD_POOL_CALLER, 0x9a, PoolType, NumberOfBytes, Tag);
89 return Block;
90 }
91
92 /*
93 * @implemented
94 */
95 PVOID NTAPI
96 ExAllocatePool (POOL_TYPE PoolType, ULONG NumberOfBytes)
97 /*
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
100 * of memory
101 * ARGUMENTS:
102 * PoolType
103 * Specifies the type of memory to allocate which can be one
104 * of the following:
105 *
106 * NonPagedPool
107 * NonPagedPoolMustSucceed
108 * NonPagedPoolCacheAligned
109 * NonPagedPoolCacheAlignedMustS
110 * PagedPool
111 * PagedPoolCacheAligned
112 *
113 * NumberOfBytes
114 * Specifies the number of bytes to allocate
115 * RETURNS: The allocated block on success
116 * NULL on failure
117 */
118 {
119 PVOID Block;
120
121 #if defined(__GNUC__)
122
123 Block = EiAllocatePool(PoolType,
124 NumberOfBytes,
125 TAG_NONE,
126 (PVOID)__builtin_return_address(0));
127 #elif defined(_MSC_VER)
128
129 Block = EiAllocatePool(PoolType,
130 NumberOfBytes,
131 TAG_NONE,
132 &ExAllocatePool);
133 #else
134 #error Unknown compiler
135 #endif
136
137 return(Block);
138 }
139
140
141 /*
142 * @implemented
143 */
144 PVOID NTAPI
145 ExAllocatePoolWithTag (POOL_TYPE PoolType, ULONG NumberOfBytes, ULONG Tag)
146 {
147 PVOID Block;
148
149 #if defined(__GNUC__)
150
151 Block = EiAllocatePool(PoolType,
152 NumberOfBytes,
153 Tag,
154 (PVOID)__builtin_return_address(0));
155 #elif defined(_MSC_VER)
156
157 Block = EiAllocatePool(PoolType,
158 NumberOfBytes,
159 Tag,
160 &ExAllocatePoolWithTag);
161 #else
162 #error Unknown compiler
163 #endif
164
165 return(Block);
166 }
167
168
169 /*
170 * @implemented
171 */
172 #undef ExAllocatePoolWithQuota
173 #undef ExAllocatePoolWithQuotaTag
174 PVOID NTAPI
175 ExAllocatePoolWithQuota (POOL_TYPE PoolType, ULONG NumberOfBytes)
176 {
177 return(ExAllocatePoolWithQuotaTag(PoolType, NumberOfBytes, TAG_NONE));
178 }
179
180 /*
181 * @implemented
182 */
183 PVOID
184 NTAPI
185 ExAllocatePoolWithTagPriority(
186 IN POOL_TYPE PoolType,
187 IN SIZE_T NumberOfBytes,
188 IN ULONG Tag,
189 IN EX_POOL_PRIORITY Priority
190 )
191 {
192 /* Do the allocation */
193 UNIMPLEMENTED;
194 return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
195 }
196
197 /*
198 * @implemented
199 */
200 PVOID
201 NTAPI
202 ExAllocatePoolWithQuotaTag (IN POOL_TYPE PoolType,
203 IN ULONG NumberOfBytes,
204 IN ULONG Tag)
205 {
206 PEPROCESS Process;
207 PVOID Block;
208
209 /* Allocate the Pool First */
210 Block = EiAllocatePool(PoolType,
211 NumberOfBytes,
212 Tag,
213 &ExAllocatePoolWithQuotaTag);
214
215 /* "Quota is not charged to the thread for allocations >= PAGE_SIZE" - OSR Docs */
216 if (!(NumberOfBytes >= PAGE_SIZE))
217 {
218 /* Get the Current Process */
219 Process = PsGetCurrentProcess();
220
221 /* PsChargePoolQuota returns an exception, so this needs SEH */
222 _SEH2_TRY
223 {
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,
227 NumberOfBytes);
228 }
229 _SEH2_EXCEPT((ExFreePool(Block), EXCEPTION_CONTINUE_SEARCH))
230 {
231 /* Quota Exceeded and the caller had no SEH! */
232 KeBugCheck(STATUS_QUOTA_EXCEEDED);
233 }
234 _SEH2_END;
235 }
236
237 /* Return the allocated block */
238 return Block;
239 }
240
241 /*
242 * @implemented
243 */
244 #undef ExFreePool
245 VOID NTAPI
246 ExFreePool(IN PVOID Block)
247 {
248 ExFreePoolWithTag(Block, 0);
249 }
250
251 VOID
252 NTAPI
253 ExFreeArmPoolWithTag(PVOID P,
254 ULONG TagToFree);
255
256 /*
257 * @implemented
258 */
259 VOID
260 NTAPI
261 ExFreePoolWithTag(
262 IN PVOID Block,
263 IN ULONG Tag)
264 {
265 /* Check for paged pool */
266 if (Block >= MmPagedPoolBase &&
267 (char*)Block < ((char*)MmPagedPoolBase + MmPagedPoolSize))
268 {
269 /* Validate tag */
270 #ifndef DEBUG_PPOOL
271 if (Tag != 0 && Tag != EiGetPagedPoolTag(Block))
272 KeBugCheckEx(BAD_POOL_CALLER,
273 0x0a,
274 (ULONG_PTR)Block,
275 EiGetPagedPoolTag(Block),
276 Tag);
277 #endif
278 /* Validate IRQL */
279 if (KeGetCurrentIrql() > APC_LEVEL)
280 KeBugCheckEx(BAD_POOL_CALLER,
281 0x09,
282 KeGetCurrentIrql(),
283 PagedPool,
284 (ULONG_PTR)Block);
285
286 /* Free from paged pool */
287 #ifdef DEBUG_PPOOL
288 if (ExpIsPoolTagDebuggable(Tag))
289 ExpFreeDebugPool(Block, TRUE);
290 else
291 #endif
292 ExFreePagedPool(Block);
293 }
294 else if (Block) return ExFreeArmPoolWithTag(Block, Tag);
295 else
296 {
297 /* Warn only for NULL pointers */
298 if (Block == NULL)
299 {
300 DPRINT1("Warning: Trying to free a NULL pointer!\n");
301 return;
302 }
303
304 /* Block was not inside any pool! */
305 KeBugCheckEx(BAD_POOL_CALLER, 0x42, (ULONG_PTR)Block, 0, 0);
306 }
307 }
308
309 /*
310 * @unimplemented
311 */
312 SIZE_T
313 NTAPI
314 ExQueryPoolBlockSize (
315 IN PVOID PoolBlock,
316 OUT PBOOLEAN QuotaCharged
317 )
318 {
319 UNIMPLEMENTED;
320 return FALSE;
321 }
322
323 /*
324 * @unimplemented
325 */
326 PVOID
327 NTAPI
328 MmAllocateMappingAddress (
329 IN SIZE_T NumberOfBytes,
330 IN ULONG PoolTag
331 )
332 {
333 UNIMPLEMENTED;
334 return 0;
335 }
336
337
338 /*
339 * @unimplemented
340 */
341 VOID
342 NTAPI
343 MmFreeMappingAddress (
344 IN PVOID BaseAddress,
345 IN ULONG PoolTag
346 )
347 {
348 UNIMPLEMENTED;
349 }
350
351 BOOLEAN
352 NTAPI
353 MiRaisePoolQuota(
354 IN POOL_TYPE PoolType,
355 IN ULONG CurrentMaxQuota,
356 OUT PULONG NewMaxQuota
357 )
358 {
359 /* Different quota raises depending on the type (64K vs 512K) */
360 if (PoolType == PagedPool) {
361
362 /* Make sure that 4MB is still left */
363 if ((MM_PAGED_POOL_SIZE >> 12) < ((MmPagedPoolSize + 4194304) >> 12)) {
364 return FALSE;
365 }
366
367 /* Increase Paged Pool Quota by 512K */
368 MmTotalPagedPoolQuota += 524288;
369 *NewMaxQuota = CurrentMaxQuota + 524288;
370 return TRUE;
371
372 } else { /* Nonpaged Pool */
373
374 /* Check if we still have 200 pages free*/
375 if (MmStats.NrFreePages < 200) return FALSE;
376
377 *NewMaxQuota = CurrentMaxQuota + 65536;
378 return TRUE;
379 }
380 }
381
382 /* EOF */