Trim cache
[reactos.git] / reactos / ntoskrnl / mm / marea.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/marea.c
22 * PURPOSE: Implements memory areas
23 * PROGRAMMER: David Welch (welch@mcmail.com)
24 * UPDATE HISTORY:
25 * Created 22/05/98
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <internal/mm.h>
32 #include <internal/ps.h>
33 #include <internal/pool.h>
34
35 #define NDEBUG
36 #include <internal/debug.h>
37
38 /* GLOBALS *******************************************************************/
39
40 #define TAG_MAREA TAG('M', 'A', 'R', 'E')
41
42 /* FUNCTIONS *****************************************************************/
43
44 VOID MmDumpMemoryAreas(PLIST_ENTRY ListHead)
45 {
46 PLIST_ENTRY current_entry;
47 MEMORY_AREA* current;
48
49 DbgPrint("MmDumpMemoryAreas()\n");
50
51 current_entry = ListHead->Flink;
52 while (current_entry!=ListHead)
53 {
54 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
55 DbgPrint("Base %x Length %x End %x Attributes %x Flink %x\n",
56 current->BaseAddress,current->Length,
57 current->BaseAddress+current->Length,current->Attributes,
58 current->Entry.Flink);
59 current_entry = current_entry->Flink;
60 }
61 DbgPrint("Finished MmDumpMemoryAreas()\n");
62 }
63
64 MEMORY_AREA* MmOpenMemoryAreaByAddress(PMADDRESS_SPACE AddressSpace,
65 PVOID Address)
66 {
67 PLIST_ENTRY current_entry;
68 MEMORY_AREA* current;
69 PLIST_ENTRY previous_entry;
70
71 DPRINT("MmOpenMemoryAreaByAddress(AddressSpace %x, Address %x)\n",
72 AddressSpace, Address);
73
74 // MmDumpMemoryAreas(&AddressSpace->MAreaListHead);
75
76 previous_entry = &AddressSpace->MAreaListHead;
77 current_entry = AddressSpace->MAreaListHead.Flink;
78 while (current_entry != &AddressSpace->MAreaListHead)
79 {
80 current = CONTAINING_RECORD(current_entry,
81 MEMORY_AREA,
82 Entry);
83 DPRINT("Scanning %x BaseAddress %x Length %x\n",
84 current, current->BaseAddress, current->Length);
85 assert(current_entry->Blink->Flink == current_entry);
86 if (current_entry->Flink->Blink != current_entry)
87 {
88 DPRINT1("BaseAddress %x\n", current->BaseAddress);
89 DPRINT1("current_entry->Flink %x ", current_entry->Flink);
90 DPRINT1("&current_entry->Flink %x\n",
91 &current_entry->Flink);
92 DPRINT1("current_entry->Flink->Blink %x\n",
93 current_entry->Flink->Blink);
94 DPRINT1("&current_entry->Flink->Blink %x\n",
95 &current_entry->Flink->Blink);
96 DPRINT1("&current_entry->Flink %x\n",
97 &current_entry->Flink);
98 }
99 assert(current_entry->Flink->Blink == current_entry);
100 assert(previous_entry->Flink == current_entry);
101 if (current->BaseAddress <= Address &&
102 (current->BaseAddress + current->Length) > Address)
103 {
104 DPRINT("%s() = %x\n",__FUNCTION__,current);
105 return(current);
106 }
107 if (current->BaseAddress > Address)
108 {
109 DPRINT("%s() = NULL\n",__FUNCTION__);
110 return(NULL);
111 }
112 previous_entry = current_entry;
113 current_entry = current_entry->Flink;
114 }
115 DPRINT("%s() = NULL\n",__FUNCTION__);
116 return(NULL);
117 }
118
119 MEMORY_AREA* MmOpenMemoryAreaByRegion(PMADDRESS_SPACE AddressSpace,
120 PVOID Address,
121 ULONG Length)
122 {
123 PLIST_ENTRY current_entry;
124 MEMORY_AREA* current;
125 ULONG Extent;
126
127 DPRINT("MmOpenMemoryByRegion(AddressSpace %x, Address %x, Length %x)\n",
128 AddressSpace, Address, Length);
129
130 current_entry = AddressSpace->MAreaListHead.Flink;
131 while (current_entry != &AddressSpace->MAreaListHead)
132 {
133 current = CONTAINING_RECORD(current_entry,
134 MEMORY_AREA,
135 Entry);
136 DPRINT("current->BaseAddress %x current->Length %x\n",
137 current->BaseAddress,current->Length);
138 if (current->BaseAddress >= Address &&
139 current->BaseAddress < (Address+Length))
140 {
141 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
142 current);
143 return(current);
144 }
145 Extent = (ULONG)current->BaseAddress + current->Length;
146 if (Extent > (ULONG)Address &&
147 Extent < (ULONG)(Address+Length))
148 {
149 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
150 current);
151 return(current);
152 }
153 if (current->BaseAddress <= Address &&
154 Extent >= (ULONG)(Address+Length))
155 {
156 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
157 current);
158 return(current);
159 }
160 if (current->BaseAddress >= (Address+Length))
161 {
162 DPRINT("Finished MmOpenMemoryAreaByRegion()= NULL\n",0);
163 return(NULL);
164 }
165 current_entry = current_entry->Flink;
166 }
167 DPRINT("Finished MmOpenMemoryAreaByRegion() = NULL\n",0);
168 return(NULL);
169 }
170
171 static VOID MmInsertMemoryArea(PMADDRESS_SPACE AddressSpace,
172 MEMORY_AREA* marea)
173 {
174 PLIST_ENTRY ListHead;
175 PLIST_ENTRY current_entry;
176 PLIST_ENTRY inserted_entry = &marea->Entry;
177 MEMORY_AREA* current;
178 MEMORY_AREA* next;
179
180 DPRINT("MmInsertMemoryArea(marea %x)\n", marea);
181 DPRINT("marea->BaseAddress %x\n", marea->BaseAddress);
182 DPRINT("marea->Length %x\n", marea->Length);
183
184 ListHead = &AddressSpace->MAreaListHead;
185
186 current_entry = ListHead->Flink;
187 CHECKPOINT;
188 if (IsListEmpty(ListHead))
189 {
190 CHECKPOINT;
191 InsertHeadList(ListHead,&marea->Entry);
192 DPRINT("Inserting at list head\n");
193 CHECKPOINT;
194 return;
195 }
196 CHECKPOINT;
197 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
198 CHECKPOINT;
199 if (current->BaseAddress > marea->BaseAddress)
200 {
201 CHECKPOINT;
202 InsertHeadList(ListHead,&marea->Entry);
203 DPRINT("Inserting at list head\n");
204 CHECKPOINT;
205 return;
206 }
207 CHECKPOINT;
208 while (current_entry->Flink!=ListHead)
209 {
210 // CHECKPOINT;
211 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
212 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
213 // assert(current->BaseAddress != marea->BaseAddress);
214 // assert(next->BaseAddress != marea->BaseAddress);
215 if (current->BaseAddress < marea->BaseAddress &&
216 current->Entry.Flink==ListHead)
217 {
218 DPRINT("Insert after %x\n", current_entry);
219 current_entry->Flink = inserted_entry;
220 inserted_entry->Flink=ListHead;
221 inserted_entry->Blink=current_entry;
222 ListHead->Blink = inserted_entry;
223 return;
224 }
225 if (current->BaseAddress < marea->BaseAddress &&
226 next->BaseAddress > marea->BaseAddress)
227 {
228 DPRINT("Inserting before %x\n", current_entry);
229 inserted_entry->Flink = current_entry->Flink;
230 inserted_entry->Blink = current_entry;
231 inserted_entry->Flink->Blink = inserted_entry;
232 current_entry->Flink=inserted_entry;
233 return;
234 }
235 current_entry = current_entry->Flink;
236 }
237 CHECKPOINT;
238 DPRINT("Inserting at list tail\n");
239 InsertTailList(ListHead,inserted_entry);
240 }
241
242 static PVOID MmFindGap(PMADDRESS_SPACE AddressSpace,
243 ULONG Length)
244 {
245 PLIST_ENTRY ListHead;
246 PLIST_ENTRY current_entry;
247 MEMORY_AREA* current;
248 MEMORY_AREA* next;
249 ULONG Gap;
250
251 DPRINT("MmFindGap(Length %x)\n",Length);
252
253 ListHead = &AddressSpace->MAreaListHead;
254
255 current_entry = ListHead->Flink;
256 while (current_entry->Flink!=ListHead)
257 {
258 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
259 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
260 DPRINT("current %x current->BaseAddress %x ",current,
261 current->BaseAddress);
262 DPRINT("current->Length %x\n",current->Length);
263 DPRINT("next %x next->BaseAddress %x ",next,next->BaseAddress);
264 Gap = (next->BaseAddress ) -(current->BaseAddress + current->Length);
265 DPRINT("Base %x Gap %x\n",current->BaseAddress,Gap);
266 if (Gap >= Length)
267 {
268 return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
269 }
270 current_entry = current_entry->Flink;
271 }
272
273 if (current_entry == ListHead)
274 {
275 return((PVOID)AddressSpace->LowestAddress);
276 }
277
278 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
279 //DbgPrint("current %x returning %x\n",current,current->BaseAddress+
280 // current->Length);
281 return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
282 }
283
284 NTSTATUS MmInitMemoryAreas(VOID)
285 /*
286 * FUNCTION: Initialize the memory area list
287 */
288 {
289 DPRINT("MmInitMemoryAreas()\n",0);
290 return(STATUS_SUCCESS);
291 }
292
293 NTSTATUS
294 MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace,
295 PVOID BaseAddress,
296 ULONG Length,
297 VOID (*FreePage)(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
298 ULONG PhysAddr),
299 PVOID FreePageContext)
300 {
301 MEMORY_AREA* MemoryArea;
302 ULONG i;
303
304 DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
305 "FreePageContext %d)\n",AddressSpace,BaseAddress,Length,FreePageContext);
306
307 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
308 BaseAddress);
309 if (MemoryArea == NULL)
310 {
311 KeBugCheck(0);
312 return(STATUS_UNSUCCESSFUL);
313 }
314 for (i=0; i<(PAGE_ROUND_UP(MemoryArea->Length)/PAGESIZE); i++)
315 {
316 ULONG PhysAddr;
317
318 PhysAddr =
319 MmGetPhysicalAddressForProcess(AddressSpace->Process,
320 MemoryArea->BaseAddress + (i*PAGESIZE));
321 MmDeleteVirtualMapping(AddressSpace->Process,
322 MemoryArea->BaseAddress + (i*PAGESIZE),
323 FALSE, NULL, NULL);
324 if (FreePage != NULL)
325 {
326 FreePage(FreePageContext, MemoryArea,
327 MemoryArea->BaseAddress + (i * PAGESIZE), PhysAddr);
328 }
329 }
330
331 RemoveEntryList(&MemoryArea->Entry);
332 ExFreePool(MemoryArea);
333
334 DPRINT("MmFreeMemoryArea() succeeded\n");
335
336 return(STATUS_SUCCESS);
337 }
338
339 PMEMORY_AREA MmSplitMemoryArea(PEPROCESS Process,
340 PMADDRESS_SPACE AddressSpace,
341 PMEMORY_AREA OriginalMemoryArea,
342 PVOID BaseAddress,
343 ULONG Length,
344 ULONG NewType,
345 ULONG NewAttributes)
346 {
347 PMEMORY_AREA Result;
348 PMEMORY_AREA Split;
349
350 Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
351 TAG_MAREA);
352 RtlZeroMemory(Result,sizeof(MEMORY_AREA));
353 Result->Type = NewType;
354 Result->BaseAddress = BaseAddress;
355 Result->Length = Length;
356 Result->Attributes = NewAttributes;
357 Result->LockCount = 0;
358 Result->Process = Process;
359
360 if (BaseAddress == OriginalMemoryArea->BaseAddress)
361 {
362 OriginalMemoryArea->BaseAddress = BaseAddress + Length;
363 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
364 MmInsertMemoryArea(AddressSpace, Result);
365 return(Result);
366 }
367 if ((BaseAddress + Length) ==
368 (OriginalMemoryArea->BaseAddress + OriginalMemoryArea->Length))
369 {
370 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
371 MmInsertMemoryArea(AddressSpace, Result);
372
373 return(Result);
374 }
375
376 Split = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
377 TAG_MAREA);
378 RtlCopyMemory(Split,OriginalMemoryArea,sizeof(MEMORY_AREA));
379 Split->BaseAddress = BaseAddress + Length;
380 Split->Length = OriginalMemoryArea->Length - (((ULONG)BaseAddress)
381 + Length);
382
383 OriginalMemoryArea->Length = BaseAddress - OriginalMemoryArea->BaseAddress;
384
385 return(Split);
386 }
387
388 NTSTATUS MmCreateMemoryArea(PEPROCESS Process,
389 PMADDRESS_SPACE AddressSpace,
390 ULONG Type,
391 PVOID* BaseAddress,
392 ULONG Length,
393 ULONG Attributes,
394 MEMORY_AREA** Result,
395 BOOL FixedAddress)
396 /*
397 * FUNCTION: Create a memory area
398 * ARGUMENTS:
399 * AddressSpace = Address space to create the area in
400 * Type = Type of the address space
401 * BaseAddress =
402 * Length = Length to allocate
403 * Attributes = Protection attributes for the memory area
404 * Result = Receives a pointer to the memory area on exit
405 * RETURNS: Status
406 * NOTES: Lock the address space before calling this function
407 */
408 {
409 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
410 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
411 Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
412
413 if ((*BaseAddress)==0 && !FixedAddress)
414 {
415 *BaseAddress = MmFindGap(AddressSpace,
416 PAGE_ROUND_UP(Length) +(PAGESIZE*2));
417 if ((*BaseAddress)==0)
418 {
419 DPRINT("No suitable gap\n");
420 return(STATUS_NO_MEMORY);
421 }
422 (*BaseAddress)=(*BaseAddress)+PAGESIZE;
423 }
424 else
425 {
426 (*BaseAddress) = (PVOID)PAGE_ROUND_DOWN((*BaseAddress));
427 if (MmOpenMemoryAreaByRegion(AddressSpace,
428 *BaseAddress,
429 Length)!=NULL)
430 {
431 DPRINT("Memory area already occupied\n");
432 return(STATUS_CONFLICTING_ADDRESSES);
433 }
434 }
435
436 *Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
437 TAG_MAREA);
438 RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
439 (*Result)->Type = Type;
440 (*Result)->BaseAddress = *BaseAddress;
441 (*Result)->Length = Length;
442 (*Result)->Attributes = Attributes;
443 (*Result)->LockCount = 0;
444 (*Result)->Process = Process;
445
446 MmInsertMemoryArea(AddressSpace, *Result);
447
448 DPRINT("MmCreateMemoryArea() succeeded\n");
449 return(STATUS_SUCCESS);
450 }