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