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