"save your files before committing them!" -> good
[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 extern ULONG MiNonPagedPoolLength;
18 extern ULONG MmTotalPagedPoolQuota;
19 extern ULONG MmTotalNonPagedPoolQuota;
20 extern MM_STATS MmStats;
21
22 /* FUNCTIONS ***************************************************************/
23
24 ULONG NTAPI
25 EiGetPagedPoolTag(IN PVOID Block);
26
27 ULONG NTAPI
28 EiGetNonPagedPoolTag(IN PVOID Block);
29
30 static PVOID STDCALL
31 EiAllocatePool(POOL_TYPE PoolType,
32 ULONG NumberOfBytes,
33 ULONG Tag,
34 PVOID Caller)
35 {
36 PVOID Block;
37 PCHAR TagChars = (PCHAR)&Tag;
38
39 if (Tag == 0)
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);
43
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);
50
51 /* FIXME: Handle SESSION_POOL_MASK, VERIFIER_POOL_MASK, QUOTA_POOL_MASK */
52 if (PoolType & PAGED_POOL_MASK)
53 {
54 if (KeGetCurrentIrql() > APC_LEVEL)
55 KeBugCheckEx(BAD_POOL_CALLER, 0x08, KeGetCurrentIrql(), PoolType, Tag);
56 Block = ExAllocatePagedPoolWithTag(PoolType, NumberOfBytes, Tag);
57 }
58 else
59 {
60 if (KeGetCurrentIrql() > DISPATCH_LEVEL)
61 KeBugCheckEx(BAD_POOL_CALLER, 0x08, KeGetCurrentIrql(), PoolType, Tag);
62 Block = ExAllocateNonPagedPoolWithTag(PoolType, NumberOfBytes, Tag, Caller);
63 }
64
65 if ((PoolType & MUST_SUCCEED_POOL_MASK) && !Block)
66 KeBugCheckEx(BAD_POOL_CALLER, 0x9a, PoolType, NumberOfBytes, Tag);
67 return Block;
68 }
69
70 /*
71 * @implemented
72 */
73 PVOID STDCALL
74 ExAllocatePool (POOL_TYPE PoolType, SIZE_T NumberOfBytes)
75 /*
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
78 * of memory
79 * ARGUMENTS:
80 * PoolType
81 * Specifies the type of memory to allocate which can be one
82 * of the following:
83 *
84 * NonPagedPool
85 * NonPagedPoolMustSucceed
86 * NonPagedPoolCacheAligned
87 * NonPagedPoolCacheAlignedMustS
88 * PagedPool
89 * PagedPoolCacheAligned
90 *
91 * NumberOfBytes
92 * Specifies the number of bytes to allocate
93 * RETURNS: The allocated block on success
94 * NULL on failure
95 */
96 {
97 PVOID Block;
98
99 #if defined(__GNUC__)
100
101 Block = EiAllocatePool(PoolType,
102 NumberOfBytes,
103 TAG_NONE,
104 (PVOID)__builtin_return_address(0));
105 #elif defined(_MSC_VER)
106
107 Block = EiAllocatePool(PoolType,
108 NumberOfBytes,
109 TAG_NONE,
110 &ExAllocatePool);
111 #else
112 #error Unknown compiler
113 #endif
114
115 return(Block);
116 }
117
118
119 /*
120 * @implemented
121 */
122 PVOID STDCALL
123 ExAllocatePoolWithTag (POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Tag)
124 {
125 PVOID Block;
126
127 #if defined(__GNUC__)
128
129 Block = EiAllocatePool(PoolType,
130 NumberOfBytes,
131 Tag,
132 (PVOID)__builtin_return_address(0));
133 #elif defined(_MSC_VER)
134
135 Block = EiAllocatePool(PoolType,
136 NumberOfBytes,
137 Tag,
138 &ExAllocatePoolWithTag);
139 #else
140 #error Unknown compiler
141 #endif
142
143 return(Block);
144 }
145
146
147 /*
148 * @implemented
149 */
150 PVOID STDCALL
151 ExAllocatePoolWithQuota (POOL_TYPE PoolType, SIZE_T NumberOfBytes)
152 {
153 return(ExAllocatePoolWithQuotaTag(PoolType, NumberOfBytes, TAG_NONE));
154 }
155
156 /*
157 * @implemented
158 */
159 PVOID
160 STDCALL
161 ExAllocatePoolWithTagPriority(
162 IN POOL_TYPE PoolType,
163 IN SIZE_T NumberOfBytes,
164 IN ULONG Tag,
165 IN EX_POOL_PRIORITY Priority
166 )
167 {
168 /* Check if this is one of the "Special" Flags, used by the Verifier */
169 if (Priority & 8) {
170 /* Check if this is a xxSpecialUnderrun */
171 if (Priority & 1) {
172 return MiAllocateSpecialPool(PoolType, NumberOfBytes, Tag, 1);
173 } else { /* xxSpecialOverrun */
174 return MiAllocateSpecialPool(PoolType, NumberOfBytes, Tag, 0);
175 }
176 }
177
178 /* FIXME: Do Ressource Checking Based on Priority and fail if resources too low*/
179
180 /* Do the allocation */
181 return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
182 }
183
184 _SEH_DEFINE_LOCALS(ExQuotaPoolVars)
185 {
186 PVOID Block;
187 };
188
189 _SEH_FILTER(FreeAndGoOn)
190 {
191 _SEH_ACCESS_LOCALS(ExQuotaPoolVars);
192
193 /* Couldn't charge, so free the pool and let the caller SEH manage */
194 ExFreePool(_SEH_VAR(Block));
195 return EXCEPTION_CONTINUE_SEARCH;
196 }
197
198 /*
199 * @implemented
200 */
201 PVOID
202 NTAPI
203 ExAllocatePoolWithQuotaTag (IN POOL_TYPE PoolType,
204 IN SIZE_T NumberOfBytes,
205 IN ULONG Tag)
206 {
207 PEPROCESS Process;
208 _SEH_DECLARE_LOCALS(ExQuotaPoolVars);
209
210 /* Allocate the Pool First */
211 _SEH_VAR(Block) = EiAllocatePool(PoolType,
212 NumberOfBytes,
213 Tag,
214 &ExAllocatePoolWithQuotaTag);
215
216 /* "Quota is not charged to the thread for allocations >= PAGE_SIZE" - OSR Docs */
217 if (!(NumberOfBytes >= PAGE_SIZE))
218 {
219 /* Get the Current Process */
220 Process = PsGetCurrentProcess();
221
222 /* PsChargePoolQuota returns an exception, so this needs SEH */
223 _SEH_TRY
224 {
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,
228 NumberOfBytes);
229 }
230 _SEH_EXCEPT(FreeAndGoOn)
231 {
232 /* Quota Exceeded and the caller had no SEH! */
233 KeBugCheck(STATUS_QUOTA_EXCEEDED);
234 }
235 _SEH_END;
236 }
237
238 /* Return the allocated block */
239 return _SEH_VAR(Block);
240 }
241
242 /*
243 * @implemented
244 */
245 #undef ExFreePool
246 VOID NTAPI
247 ExFreePool(IN PVOID Block)
248 {
249 if (Block >= MmPagedPoolBase && (char*)Block < ((char*)MmPagedPoolBase + MmPagedPoolSize))
250 {
251 if (KeGetCurrentIrql() > APC_LEVEL)
252 KeBugCheckEx(BAD_POOL_CALLER, 0x09, KeGetCurrentIrql(), PagedPool, (ULONG_PTR)Block);
253 ExFreePagedPool(Block);
254 }
255 else
256 {
257 if (KeGetCurrentIrql() > DISPATCH_LEVEL)
258 KeBugCheckEx(BAD_POOL_CALLER, 0x09, KeGetCurrentIrql(), NonPagedPool, (ULONG_PTR)Block);
259 ExFreeNonPagedPool(Block);
260 }
261 }
262
263 /*
264 * @implemented
265 */
266 VOID NTAPI
267 ExFreePoolWithTag(IN PVOID Block, IN ULONG Tag)
268 {
269 ULONG BlockTag;
270
271 if (Block >= MmPagedPoolBase && (char*)Block < ((char*)MmPagedPoolBase + MmPagedPoolSize))
272 BlockTag = EiGetPagedPoolTag(Block);
273 else
274 BlockTag = EiGetNonPagedPoolTag(Block);
275
276 if (BlockTag != Tag)
277 KeBugCheckEx(BAD_POOL_CALLER, 0x0a, (ULONG_PTR)Block, BlockTag, Tag);
278
279 ExFreePool(Block);
280 }
281
282 /*
283 * @unimplemented
284 */
285 SIZE_T
286 STDCALL
287 ExQueryPoolBlockSize (
288 IN PVOID PoolBlock,
289 OUT PBOOLEAN QuotaCharged
290 )
291 {
292 UNIMPLEMENTED;
293 return FALSE;
294 }
295
296 /*
297 * @unimplemented
298 */
299 PVOID
300 STDCALL
301 MmAllocateMappingAddress (
302 IN SIZE_T NumberOfBytes,
303 IN ULONG PoolTag
304 )
305 {
306 UNIMPLEMENTED;
307 return 0;
308 }
309
310
311 /*
312 * @unimplemented
313 */
314 VOID
315 STDCALL
316 MmFreeMappingAddress (
317 IN PVOID BaseAddress,
318 IN ULONG PoolTag
319 )
320 {
321 UNIMPLEMENTED;
322 }
323
324 BOOLEAN
325 STDCALL
326 MiRaisePoolQuota(
327 IN POOL_TYPE PoolType,
328 IN ULONG CurrentMaxQuota,
329 OUT PULONG NewMaxQuota
330 )
331 {
332 /* Different quota raises depending on the type (64K vs 512K) */
333 if (PoolType == PagedPool) {
334
335 /* Make sure that 4MB is still left */
336 if ((MM_PAGED_POOL_SIZE >> 12) < ((MmPagedPoolSize + 4194304) >> 12)) {
337 return FALSE;
338 }
339
340 /* Increase Paged Pool Quota by 512K */
341 MmTotalPagedPoolQuota += 524288;
342 *NewMaxQuota = CurrentMaxQuota + 524288;
343 return TRUE;
344
345 } else { /* Nonpaged Pool */
346
347 /* Check if we still have 200 pages free*/
348 if (MmStats.NrFreePages < 200) return FALSE;
349
350 /* Check that 4MB is still left */
351 if ((MM_NONPAGED_POOL_SIZE >> 12) < ((MiNonPagedPoolLength + 4194304) >> 12)) {
352 return FALSE;
353 }
354
355 /* Increase Non Paged Pool Quota by 64K */
356 MmTotalNonPagedPoolQuota += 65536;
357 *NewMaxQuota = CurrentMaxQuota + 65536;
358 return TRUE;
359 }
360 }
361
362 /* EOF */