98a62bc0f9b0b1fe69b4d47dd311a39ded4bbb6a
[reactos.git] / reactos / ntoskrnl / mm / pool.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/pool.c
6 * PURPOSE: Implements the kernel memory pool
7 * PROGRAMMER: David Welch (welch@mcmail.com)
8 */
9
10 /* INCLUDES ****************************************************************/
11
12 #include <ntoskrnl.h>
13
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 extern ULONG MiNonPagedPoolLength;
18 extern ULONG MmTotalPagedPoolQuota;
19 extern ULONG MmTotalNonPagedPoolQuota;
20 extern MM_STATS MmStats;
21
22 /* GLOBALS *****************************************************************/
23
24 #define TAG_NONE (ULONG)(('N'<<0) + ('o'<<8) + ('n'<<16) + ('e'<<24))
25
26 ULONG STDCALL
27 ExRosQueryPagedPoolTag ( PVOID Block );
28
29 /* FUNCTIONS ***************************************************************/
30
31 STATIC PVOID STDCALL
32 EiAllocatePool(POOL_TYPE PoolType,
33 ULONG NumberOfBytes,
34 ULONG Tag,
35 PVOID Caller)
36 {
37 PVOID Block;
38
39
40 switch(PoolType)
41 {
42 case NonPagedPool:
43 case NonPagedPoolMustSucceed:
44 case NonPagedPoolCacheAligned:
45 case NonPagedPoolCacheAlignedMustS:
46 Block =
47 ExAllocateNonPagedPoolWithTag(PoolType,
48 NumberOfBytes,
49 Tag,
50 Caller);
51 break;
52
53 case PagedPool:
54 case PagedPoolCacheAligned:
55 Block = ExAllocatePagedPoolWithTag(PoolType,NumberOfBytes,Tag);
56 break;
57
58 default:
59 return(NULL);
60 };
61
62 if ((PoolType==NonPagedPoolMustSucceed ||
63 PoolType==NonPagedPoolCacheAlignedMustS) && Block==NULL)
64 {
65 KEBUGCHECK(MUST_SUCCEED_POOL_EMPTY);
66 }
67 return(Block);
68 }
69
70 /*
71 * @implemented
72 */
73 PVOID STDCALL
74 ExAllocatePool (POOL_TYPE PoolType, ULONG 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, ULONG 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, ULONG 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 /*
185 * @implemented
186 */
187 PVOID STDCALL
188 ExAllocatePoolWithQuotaTag (IN POOL_TYPE PoolType,
189 IN ULONG NumberOfBytes,
190 IN ULONG Tag)
191 {
192 PVOID Block;
193 PEPROCESS Process;
194
195 /* Allocate the Pool First */
196 Block = EiAllocatePool(PoolType,
197 NumberOfBytes,
198 Tag,
199 &ExAllocatePoolWithQuotaTag);
200
201 /* "Quota is not charged to the thread for allocations >= PAGE_SIZE" - OSR Docs */
202 if (!(NumberOfBytes >= PAGE_SIZE)) {
203
204 /* Get the Current Process */
205 Process = PsGetCurrentProcess();
206
207 /* PsChargePoolQuota returns an exception, so this needs SEH */
208 #if defined(__GNUC__)
209 _SEH_FILTER(FreeAndGoOn) {
210 /* Couldn't charge, so free the pool and let the caller SEH manage */
211 ExFreePool(Block);
212 return EXCEPTION_CONTINUE_SEARCH;
213 } _SEH_TRY_FILTER(FreeAndGoOn) {
214 //* FIXME: Is there a way to get the actual Pool size allocated from the pool header? */
215 PsChargePoolQuota(Process, PoolType, NumberOfBytes);
216 } _SEH_HANDLE {
217 /* Quota Exceeded and the caller had no SEH! */
218 KeBugCheck(STATUS_QUOTA_EXCEEDED);
219 } _SEH_END;
220 #else /* assuming all other Win32 compilers understand SEH */
221 __try {
222 PsChargePoolQuota(Process, PoolType, NumberOfBytes);
223 }
224 __except (ExFreePool(Block), EXCEPTION_CONTINUE_SEARCH) {
225 KeBugCheck(STATUS_QUOTA_EXCEEDED);
226 }
227 #endif
228 }
229
230 return Block;
231 }
232
233 /*
234 * @implemented
235 */
236 VOID STDCALL
237 ExFreePool(IN PVOID Block)
238 {
239 ASSERT_IRQL(DISPATCH_LEVEL);
240
241 if (Block >= MmPagedPoolBase && (char*)Block < ((char*)MmPagedPoolBase + MmPagedPoolSize))
242 {
243 ExFreePagedPool(Block);
244 }
245 else
246 {
247 ExFreeNonPagedPool(Block);
248 }
249 }
250
251 /*
252 * @implemented
253 */
254 VOID STDCALL
255 ExFreePoolWithTag(IN PVOID Block, IN ULONG Tag)
256 {
257 /* FIXME: Validate the tag */
258 ExFreePool(Block);
259 }
260
261 /*
262 * @unimplemented
263 */
264 SIZE_T
265 STDCALL
266 ExQueryPoolBlockSize (
267 IN PVOID PoolBlock,
268 OUT PBOOLEAN QuotaCharged
269 )
270 {
271 UNIMPLEMENTED;
272 return FALSE;
273 }
274
275 /*
276 * @unimplemented
277 */
278 PVOID
279 STDCALL
280 MmAllocateMappingAddress (
281 IN SIZE_T NumberOfBytes,
282 IN ULONG PoolTag
283 )
284 {
285 UNIMPLEMENTED;
286 return 0;
287 }
288
289
290 /*
291 * @unimplemented
292 */
293 VOID
294 STDCALL
295 MmFreeMappingAddress (
296 IN PVOID BaseAddress,
297 IN ULONG PoolTag
298 )
299 {
300 UNIMPLEMENTED;
301 }
302
303 BOOLEAN
304 STDCALL
305 MiRaisePoolQuota(
306 IN POOL_TYPE PoolType,
307 IN ULONG CurrentMaxQuota,
308 OUT PULONG NewMaxQuota
309 )
310 {
311 /* Different quota raises depending on the type (64K vs 512K) */
312 if (PoolType == PagedPool) {
313
314 /* Make sure that 4MB is still left */
315 if ((MM_PAGED_POOL_SIZE >> 12) < ((MmPagedPoolSize + 4194304) >> 12)) {
316 return FALSE;
317 }
318
319 /* Increase Paged Pool Quota by 512K */
320 MmTotalPagedPoolQuota += 524288;
321 *NewMaxQuota = CurrentMaxQuota + 524288;
322 return TRUE;
323
324 } else { /* Nonpaged Pool */
325
326 /* Check if we still have 200 pages free*/
327 if (MmStats.NrFreePages < 200) return FALSE;
328
329 /* Check that 4MB is still left */
330 if ((MM_NONPAGED_POOL_SIZE >> 12) < ((MiNonPagedPoolLength + 4194304) >> 12)) {
331 return FALSE;
332 }
333
334 /* Increase Non Paged Pool Quota by 64K */
335 MmTotalNonPagedPoolQuota += 65536;
336 *NewMaxQuota = CurrentMaxQuota + 65536;
337 return TRUE;
338 }
339 }
340
341 ULONG STDCALL
342 ExRosQueryPoolTag ( PVOID Block )
343 {
344 ASSERT_IRQL(DISPATCH_LEVEL);
345
346 if (Block >= MmPagedPoolBase && (char*)Block < ((char*)MmPagedPoolBase + MmPagedPoolSize))
347 {
348 return ExRosQueryPagedPoolTag(Block);
349 }
350 else
351 {
352 UNIMPLEMENTED;
353 return 0;
354 }
355 }
356
357 /* EOF */