Add -Wno-format to dmusic
[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 static PVOID NTAPI
37 EiAllocatePool(POOL_TYPE PoolType,
38 ULONG NumberOfBytes,
39 ULONG Tag,
40 PVOID Caller)
41 {
42 PVOID Block;
43 PCHAR TagChars = (PCHAR)&Tag;
44
45 if (Tag == 0)
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);
49
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);
56
57 /* FIXME: Handle SESSION_POOL_MASK, VERIFIER_POOL_MASK, QUOTA_POOL_MASK */
58 if (PoolType & PAGED_POOL_MASK)
59 {
60 if (KeGetCurrentIrql() > APC_LEVEL)
61 KeBugCheckEx(BAD_POOL_CALLER, 0x08, KeGetCurrentIrql(), PoolType, Tag);
62 #ifdef DEBUG_PPOOL
63 if (ExpIsPoolTagDebuggable(Tag))
64 Block = ExpAllocateDebugPool(PoolType, NumberOfBytes, Tag, Caller, TRUE);
65 else
66 #endif
67 Block = ExAllocatePagedPoolWithTag(PoolType, NumberOfBytes, Tag);
68 }
69 else
70 {
71 if (KeGetCurrentIrql() > DISPATCH_LEVEL)
72 KeBugCheckEx(BAD_POOL_CALLER, 0x08, KeGetCurrentIrql(), PoolType, Tag);
73 #ifdef DEBUG_NPOOL
74 if (ExpIsPoolTagDebuggable(Tag))
75 Block = ExpAllocateDebugPool(PoolType, NumberOfBytes, Tag, Caller, TRUE);
76 else
77 #endif
78 Block = ExAllocateNonPagedPoolWithTag(PoolType, NumberOfBytes, Tag, Caller);
79 }
80
81 if ((PoolType & MUST_SUCCEED_POOL_MASK) && !Block)
82 KeBugCheckEx(BAD_POOL_CALLER, 0x9a, PoolType, NumberOfBytes, Tag);
83 return Block;
84 }
85
86 /*
87 * @implemented
88 */
89 PVOID NTAPI
90 ExAllocatePool (POOL_TYPE PoolType, SIZE_T NumberOfBytes)
91 /*
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
94 * of memory
95 * ARGUMENTS:
96 * PoolType
97 * Specifies the type of memory to allocate which can be one
98 * of the following:
99 *
100 * NonPagedPool
101 * NonPagedPoolMustSucceed
102 * NonPagedPoolCacheAligned
103 * NonPagedPoolCacheAlignedMustS
104 * PagedPool
105 * PagedPoolCacheAligned
106 *
107 * NumberOfBytes
108 * Specifies the number of bytes to allocate
109 * RETURNS: The allocated block on success
110 * NULL on failure
111 */
112 {
113 PVOID Block;
114
115 #if defined(__GNUC__)
116
117 Block = EiAllocatePool(PoolType,
118 NumberOfBytes,
119 TAG_NONE,
120 (PVOID)__builtin_return_address(0));
121 #elif defined(_MSC_VER)
122
123 Block = EiAllocatePool(PoolType,
124 NumberOfBytes,
125 TAG_NONE,
126 &ExAllocatePool);
127 #else
128 #error Unknown compiler
129 #endif
130
131 return(Block);
132 }
133
134
135 /*
136 * @implemented
137 */
138 PVOID NTAPI
139 ExAllocatePoolWithTag (POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Tag)
140 {
141 PVOID Block;
142
143 #if defined(__GNUC__)
144
145 Block = EiAllocatePool(PoolType,
146 NumberOfBytes,
147 Tag,
148 (PVOID)__builtin_return_address(0));
149 #elif defined(_MSC_VER)
150
151 Block = EiAllocatePool(PoolType,
152 NumberOfBytes,
153 Tag,
154 &ExAllocatePoolWithTag);
155 #else
156 #error Unknown compiler
157 #endif
158
159 return(Block);
160 }
161
162
163 /*
164 * @implemented
165 */
166 #undef ExAllocatePoolWithQuota
167 PVOID NTAPI
168 ExAllocatePoolWithQuota (POOL_TYPE PoolType, SIZE_T NumberOfBytes)
169 {
170 return(ExAllocatePoolWithQuotaTag(PoolType, NumberOfBytes, TAG_NONE));
171 }
172
173 /*
174 * @implemented
175 */
176 PVOID
177 NTAPI
178 ExAllocatePoolWithTagPriority(
179 IN POOL_TYPE PoolType,
180 IN SIZE_T NumberOfBytes,
181 IN ULONG Tag,
182 IN EX_POOL_PRIORITY Priority
183 )
184 {
185 /* Check if this is one of the "Special" Flags, used by the Verifier */
186 if (Priority & 8) {
187 /* Check if this is a xxSpecialUnderrun */
188 if (Priority & 1) {
189 return MiAllocateSpecialPool(PoolType, NumberOfBytes, Tag, 1);
190 } else { /* xxSpecialOverrun */
191 return MiAllocateSpecialPool(PoolType, NumberOfBytes, Tag, 0);
192 }
193 }
194
195 /* FIXME: Do Ressource Checking Based on Priority and fail if resources too low*/
196
197 /* Do the allocation */
198 return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
199 }
200
201 /*
202 * @implemented
203 */
204 #undef ExAllocatePoolWithQuotaTag
205 PVOID
206 NTAPI
207 ExAllocatePoolWithQuotaTag (IN POOL_TYPE PoolType,
208 IN SIZE_T NumberOfBytes,
209 IN ULONG Tag)
210 {
211 PEPROCESS Process;
212 PVOID Block;
213
214 /* Allocate the Pool First */
215 Block = EiAllocatePool(PoolType,
216 NumberOfBytes,
217 Tag,
218 &ExAllocatePoolWithQuotaTag);
219
220 /* "Quota is not charged to the thread for allocations >= PAGE_SIZE" - OSR Docs */
221 if (!(NumberOfBytes >= PAGE_SIZE))
222 {
223 /* Get the Current Process */
224 Process = PsGetCurrentProcess();
225
226 /* PsChargePoolQuota returns an exception, so this needs SEH */
227 _SEH2_TRY
228 {
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,
232 NumberOfBytes);
233 }
234 _SEH2_EXCEPT((ExFreePool(Block), EXCEPTION_CONTINUE_SEARCH))
235 {
236 /* Quota Exceeded and the caller had no SEH! */
237 KeBugCheck(STATUS_QUOTA_EXCEEDED);
238 }
239 _SEH2_END;
240 }
241
242 /* Return the allocated block */
243 return Block;
244 }
245
246 /*
247 * @implemented
248 */
249 #undef ExFreePool
250 VOID NTAPI
251 ExFreePool(IN PVOID Block)
252 {
253 ExFreePoolWithTag(Block, 0);
254 }
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
295 /* Check for non-paged pool */
296 else if (Block >= MiNonPagedPoolStart &&
297 (char*)Block < ((char*)MiNonPagedPoolStart + MiNonPagedPoolLength))
298 {
299 /* Validate tag */
300 #ifndef DEBUG_NPOOL
301 if (Tag != 0 && Tag != EiGetNonPagedPoolTag(Block))
302 KeBugCheckEx(BAD_POOL_CALLER,
303 0x0a,
304 (ULONG_PTR)Block,
305 EiGetNonPagedPoolTag(Block),
306 Tag);
307 #endif
308 /* Validate IRQL */
309 if (KeGetCurrentIrql() > DISPATCH_LEVEL)
310 KeBugCheckEx(BAD_POOL_CALLER,
311 0x09,
312 KeGetCurrentIrql(),
313 NonPagedPool,
314 (ULONG_PTR)Block);
315
316 /* Free from non-paged pool */
317 #ifdef DEBUG_NPOOL
318 if (ExpIsPoolTagDebuggable(Tag))
319 ExpFreeDebugPool(Block, FALSE);
320 else
321 #endif
322 ExFreeNonPagedPool(Block);
323 }
324 else
325 {
326 /* Warn only for NULL pointers */
327 if (Block == NULL)
328 {
329 DPRINT1("Warning: Trying to free a NULL pointer!\n");
330 return;
331 }
332
333 /* Block was not inside any pool! */
334 KeBugCheckEx(BAD_POOL_CALLER, 0x42, (ULONG_PTR)Block, 0, 0);
335 }
336 }
337
338 /*
339 * @unimplemented
340 */
341 SIZE_T
342 NTAPI
343 ExQueryPoolBlockSize (
344 IN PVOID PoolBlock,
345 OUT PBOOLEAN QuotaCharged
346 )
347 {
348 UNIMPLEMENTED;
349 return FALSE;
350 }
351
352 /*
353 * @unimplemented
354 */
355 PVOID
356 NTAPI
357 MmAllocateMappingAddress (
358 IN SIZE_T NumberOfBytes,
359 IN ULONG PoolTag
360 )
361 {
362 UNIMPLEMENTED;
363 return 0;
364 }
365
366
367 /*
368 * @unimplemented
369 */
370 VOID
371 NTAPI
372 MmFreeMappingAddress (
373 IN PVOID BaseAddress,
374 IN ULONG PoolTag
375 )
376 {
377 UNIMPLEMENTED;
378 }
379
380 BOOLEAN
381 NTAPI
382 MiRaisePoolQuota(
383 IN POOL_TYPE PoolType,
384 IN ULONG CurrentMaxQuota,
385 OUT PULONG NewMaxQuota
386 )
387 {
388 /* Different quota raises depending on the type (64K vs 512K) */
389 if (PoolType == PagedPool) {
390
391 /* Make sure that 4MB is still left */
392 if ((MM_PAGED_POOL_SIZE >> 12) < ((MmPagedPoolSize + 4194304) >> 12)) {
393 return FALSE;
394 }
395
396 /* Increase Paged Pool Quota by 512K */
397 MmTotalPagedPoolQuota += 524288;
398 *NewMaxQuota = CurrentMaxQuota + 524288;
399 return TRUE;
400
401 } else { /* Nonpaged Pool */
402
403 /* Check if we still have 200 pages free*/
404 if (MmStats.NrFreePages < 200) return FALSE;
405
406 /* Check that 4MB is still left */
407 if ((MM_NONPAGED_POOL_SIZE >> 12) < ((MiNonPagedPoolLength + 4194304) >> 12)) {
408 return FALSE;
409 }
410
411 /* Increase Non Paged Pool Quota by 64K */
412 MmTotalNonPagedPoolQuota += 65536;
413 *NewMaxQuota = CurrentMaxQuota + 65536;
414 return TRUE;
415 }
416 }
417
418 /* EOF */