indent using astyle v1.15.3: astyle --style=ansi -c -s3 -S --convert-tabs %1
[reactos.git] / reactos / ntoskrnl / mm / marea.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001, 2003 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 (char*)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 previous_entry = &AddressSpace->MAreaListHead;
75 current_entry = AddressSpace->MAreaListHead.Flink;
76 while (current_entry != &AddressSpace->MAreaListHead)
77 {
78 current = CONTAINING_RECORD(current_entry,
79 MEMORY_AREA,
80 Entry);
81 assert(current_entry->Blink->Flink == current_entry);
82 assert(current_entry->Flink->Blink == current_entry);
83 assert(previous_entry->Flink == current_entry);
84 if (current->BaseAddress <= Address &&
85 (PVOID)((char*)current->BaseAddress + current->Length) > Address)
86 {
87 DPRINT("%s() = %x\n",__FUNCTION__,current);
88 return(current);
89 }
90 if (current->BaseAddress > Address)
91 {
92 DPRINT("%s() = NULL\n",__FUNCTION__);
93 return(NULL);
94 }
95 previous_entry = current_entry;
96 current_entry = current_entry->Flink;
97 }
98 DPRINT("%s() = NULL\n",__FUNCTION__);
99 return(NULL);
100 }
101
102 MEMORY_AREA* MmOpenMemoryAreaByRegion(PMADDRESS_SPACE AddressSpace,
103 PVOID Address,
104 ULONG Length)
105 {
106 PLIST_ENTRY current_entry;
107 MEMORY_AREA* current;
108 ULONG Extent;
109
110 DPRINT("MmOpenMemoryByRegion(AddressSpace %x, Address %x, Length %x)\n",
111 AddressSpace, Address, Length);
112
113 current_entry = AddressSpace->MAreaListHead.Flink;
114 while (current_entry != &AddressSpace->MAreaListHead)
115 {
116 current = CONTAINING_RECORD(current_entry,
117 MEMORY_AREA,
118 Entry);
119 DPRINT("current->BaseAddress %x current->Length %x\n",
120 current->BaseAddress,current->Length);
121 if (current->BaseAddress >= Address &&
122 current->BaseAddress < (PVOID)((char*)Address+Length))
123 {
124 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
125 current);
126 return(current);
127 }
128 Extent = (ULONG)current->BaseAddress + current->Length;
129 if (Extent > (ULONG)Address &&
130 Extent < (ULONG)((char*)Address+Length))
131 {
132 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
133 current);
134 return(current);
135 }
136 if (current->BaseAddress <= Address &&
137 Extent >= (ULONG)((char*)Address+Length))
138 {
139 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
140 current);
141 return(current);
142 }
143 if (current->BaseAddress >= (PVOID)((char*)Address+Length))
144 {
145 DPRINT("Finished MmOpenMemoryAreaByRegion()= NULL\n",0);
146 return(NULL);
147 }
148 current_entry = current_entry->Flink;
149 }
150 DPRINT("Finished MmOpenMemoryAreaByRegion() = NULL\n",0);
151 return(NULL);
152 }
153
154 static VOID MmInsertMemoryArea(PMADDRESS_SPACE AddressSpace,
155 MEMORY_AREA* marea)
156 {
157 PLIST_ENTRY ListHead;
158 PLIST_ENTRY current_entry;
159 PLIST_ENTRY inserted_entry = &marea->Entry;
160 MEMORY_AREA* current;
161 MEMORY_AREA* next;
162
163 DPRINT("MmInsertMemoryArea(marea %x)\n", marea);
164 DPRINT("marea->BaseAddress %x\n", marea->BaseAddress);
165 DPRINT("marea->Length %x\n", marea->Length);
166
167 ListHead = &AddressSpace->MAreaListHead;
168
169 current_entry = ListHead->Flink;
170 if (IsListEmpty(ListHead))
171 {
172 InsertHeadList(ListHead,&marea->Entry);
173 return;
174 }
175 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
176 if (current->BaseAddress > marea->BaseAddress)
177 {
178 InsertHeadList(ListHead,&marea->Entry);
179 return;
180 }
181 while (current_entry->Flink!=ListHead)
182 {
183 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
184 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
185 if (current->BaseAddress < marea->BaseAddress &&
186 current->Entry.Flink==ListHead)
187 {
188 current_entry->Flink = inserted_entry;
189 inserted_entry->Flink=ListHead;
190 inserted_entry->Blink=current_entry;
191 ListHead->Blink = inserted_entry;
192 return;
193 }
194 if (current->BaseAddress < marea->BaseAddress &&
195 next->BaseAddress > marea->BaseAddress)
196 {
197 inserted_entry->Flink = current_entry->Flink;
198 inserted_entry->Blink = current_entry;
199 inserted_entry->Flink->Blink = inserted_entry;
200 current_entry->Flink=inserted_entry;
201 return;
202 }
203 current_entry = current_entry->Flink;
204 }
205 InsertTailList(ListHead,inserted_entry);
206 }
207
208
209 PVOID MmFindGapBottomUp(PMADDRESS_SPACE AddressSpace, ULONG Length)
210 {
211 PLIST_ENTRY ListHead;
212 PLIST_ENTRY current_entry;
213 MEMORY_AREA* current;
214 MEMORY_AREA* next;
215 ULONG Gap;
216 PVOID Address;
217
218 DPRINT("MmFindGapBottomUp(Length %x)\n",Length);
219
220 ListHead = &AddressSpace->MAreaListHead;
221
222 current_entry = ListHead->Flink;
223 while (current_entry->Flink!=ListHead)
224 {
225 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
226 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
227 Gap = (char*)next->BaseAddress - ((char*)current->BaseAddress + PAGE_ROUND_UP(current->Length));
228 if (Gap >= Length)
229 {
230 return((char*)current->BaseAddress + PAGE_ROUND_UP(current->Length));
231 }
232 current_entry = current_entry->Flink;
233 }
234
235 if (current_entry == ListHead)
236 {
237 Address = (PVOID)AddressSpace->LowestAddress;
238 }
239 else
240 {
241 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
242 Address = (char*)current->BaseAddress + PAGE_ROUND_UP(current->Length);
243 }
244 /* Check if enough space for the block */
245 if (AddressSpace->LowestAddress < KERNEL_BASE)
246 {
247 if ((ULONG)Address >= KERNEL_BASE || Length > KERNEL_BASE - (ULONG)Address)
248 {
249 return NULL;
250 }
251 }
252 else
253 {
254 if (Length >= 0xFFFFFFFF - (ULONG)Address)
255 {
256 return NULL;
257 }
258 }
259 return Address;
260 }
261
262
263 PVOID MmFindGapTopDown(PMADDRESS_SPACE AddressSpace, ULONG Length)
264 {
265 PLIST_ENTRY ListHead;
266 PLIST_ENTRY current_entry;
267 MEMORY_AREA* current;
268 ULONG Gap;
269 PVOID Address;
270 PVOID TopAddress;
271 PVOID BottomAddress;
272 PVOID HighestAddress;
273
274 DPRINT("MmFindGapTopDown(Length %lx)\n",Length);
275
276 if (AddressSpace->LowestAddress < KERNEL_BASE) //(ULONG_PTR)MmSystemRangeStart)
277 {
278 HighestAddress = MmHighestUserAddress;
279 }
280 else
281 {
282 HighestAddress = (PVOID)0xFFFFFFFF;
283 }
284
285 TopAddress = HighestAddress;
286
287 ListHead = &AddressSpace->MAreaListHead;
288 current_entry = ListHead->Blink;
289 while (current_entry->Blink != ListHead)
290 {
291 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
292 BottomAddress = (char*)current->BaseAddress + PAGE_ROUND_UP(current->Length);
293 DPRINT("Base %p Length %lx\n", current->BaseAddress, PAGE_ROUND_UP(current->Length));
294
295 if (BottomAddress < HighestAddress)
296 {
297 Gap = (char*)TopAddress - (char*)BottomAddress + 1;
298 DPRINT("Bottom %p Top %p Gap %lx\n", BottomAddress, TopAddress, Gap);
299 if (Gap >= Length)
300 {
301 DPRINT("Found gap at %p\n", (char*)TopAddress - Length);
302 return((char*)TopAddress - Length + 1);
303 }
304 TopAddress = (char*)current->BaseAddress - 1;
305 }
306 current_entry = current_entry->Blink;
307 }
308
309 if (current_entry == ListHead)
310 {
311 Address = (char*)HighestAddress - Length + 1;
312 }
313 else
314 {
315 Address = (char*)TopAddress - Length + 1;
316 }
317
318 /* Check if enough space for the block */
319 if (AddressSpace->LowestAddress < KERNEL_BASE)
320 {
321 if ((ULONG)Address >= KERNEL_BASE || Length > KERNEL_BASE - (ULONG)Address)
322 {
323 DPRINT("Failed to find gap\n");
324 return NULL;
325 }
326 }
327 else
328 {
329 if (Length >= 0xFFFFFFFF - (ULONG)Address)
330 {
331 DPRINT("Failed to find gap\n");
332 return NULL;
333 }
334 }
335
336 DPRINT("Found gap at %p\n", Address);
337 return Address;
338 }
339
340
341 PVOID MmFindGap(PMADDRESS_SPACE AddressSpace, ULONG Length, BOOL TopDown)
342 {
343 if (TopDown)
344 return MmFindGapTopDown(AddressSpace, Length);
345
346 return MmFindGapBottomUp(AddressSpace, Length);
347 }
348
349
350 NTSTATUS INIT_FUNCTION
351 MmInitMemoryAreas(VOID)
352 /*
353 * FUNCTION: Initialize the memory area list
354 */
355 {
356 DPRINT("MmInitMemoryAreas()\n",0);
357 return(STATUS_SUCCESS);
358 }
359
360 NTSTATUS
361 MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace,
362 PVOID BaseAddress,
363 ULONG Length,
364 VOID (*FreePage)(PVOID Context, MEMORY_AREA* MemoryArea,
365 PVOID Address, PHYSICAL_ADDRESS PhysAddr,
366 SWAPENTRY SwapEntry, BOOLEAN Dirty),
367 PVOID FreePageContext)
368 {
369 MEMORY_AREA* MemoryArea;
370 ULONG i;
371 PEPROCESS CurrentProcess = PsGetCurrentProcess();
372
373 DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
374 "FreePageContext %d)\n",AddressSpace,BaseAddress,Length,
375 FreePageContext);
376
377 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
378 BaseAddress);
379 if (MemoryArea == NULL)
380 {
381 KEBUGCHECK(0);
382 return(STATUS_UNSUCCESSFUL);
383 }
384 if (AddressSpace->Process != NULL &&
385 AddressSpace->Process != CurrentProcess)
386 {
387 KeAttachProcess(AddressSpace->Process);
388 }
389 for (i=0; i<(PAGE_ROUND_UP(MemoryArea->Length)/PAGE_SIZE); i++)
390 {
391 #if defined(__GNUC__)
392 PHYSICAL_ADDRESS PhysAddr = (PHYSICAL_ADDRESS)0LL;
393 #else
394
395 PHYSICAL_ADDRESS PhysAddr = { 0 };
396 #endif
397
398 BOOL Dirty = FALSE;
399 SWAPENTRY SwapEntry = 0;
400
401 if (MmIsPageSwapEntry(AddressSpace->Process,
402 (char*)MemoryArea->BaseAddress + (i * PAGE_SIZE)))
403 {
404 MmDeletePageFileMapping(AddressSpace->Process,
405 (char*)MemoryArea->BaseAddress + (i * PAGE_SIZE),
406 &SwapEntry);
407 }
408 else
409 {
410 MmDeleteVirtualMapping(AddressSpace->Process,
411 (char*)MemoryArea->BaseAddress + (i*PAGE_SIZE),
412 FALSE, &Dirty, &PhysAddr);
413
414 }
415 if (FreePage != NULL)
416 {
417 FreePage(FreePageContext, MemoryArea,
418 (char*)MemoryArea->BaseAddress + (i * PAGE_SIZE), PhysAddr,
419 SwapEntry, (BOOLEAN)Dirty);
420 }
421 }
422 if (AddressSpace->Process != NULL &&
423 AddressSpace->Process != CurrentProcess)
424 {
425 KeDetachProcess();
426 }
427 RemoveEntryList(&MemoryArea->Entry);
428 ExFreePool(MemoryArea);
429
430 DPRINT("MmFreeMemoryArea() succeeded\n");
431
432 return(STATUS_SUCCESS);
433 }
434
435 PMEMORY_AREA MmSplitMemoryArea(PEPROCESS Process,
436 PMADDRESS_SPACE AddressSpace,
437 PMEMORY_AREA OriginalMemoryArea,
438 PVOID BaseAddress,
439 ULONG Length,
440 ULONG NewType,
441 ULONG NewAttributes)
442 {
443 PMEMORY_AREA Result;
444 PMEMORY_AREA Split;
445
446 Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
447 TAG_MAREA);
448 RtlZeroMemory(Result,sizeof(MEMORY_AREA));
449 Result->Type = NewType;
450 Result->BaseAddress = BaseAddress;
451 Result->Length = Length;
452 Result->Attributes = NewAttributes;
453 Result->LockCount = 0;
454 Result->Process = Process;
455
456 if (BaseAddress == OriginalMemoryArea->BaseAddress)
457 {
458 OriginalMemoryArea->BaseAddress = (char*)BaseAddress + Length;
459 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
460 MmInsertMemoryArea(AddressSpace, Result);
461 return(Result);
462 }
463 if (((char*)BaseAddress + Length) ==
464 ((char*)OriginalMemoryArea->BaseAddress + OriginalMemoryArea->Length))
465 {
466 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
467 MmInsertMemoryArea(AddressSpace, Result);
468
469 return(Result);
470 }
471
472 Split = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
473 TAG_MAREA);
474 RtlCopyMemory(Split,OriginalMemoryArea,sizeof(MEMORY_AREA));
475 Split->BaseAddress = (char*)BaseAddress + Length;
476 Split->Length = OriginalMemoryArea->Length - (((ULONG)BaseAddress)
477 + Length);
478
479 OriginalMemoryArea->Length = (char*)BaseAddress - (char*)OriginalMemoryArea->BaseAddress;
480
481 return(Split);
482 }
483
484 NTSTATUS MmCreateMemoryArea(PEPROCESS Process,
485 PMADDRESS_SPACE AddressSpace,
486 ULONG Type,
487 PVOID* BaseAddress,
488 ULONG Length,
489 ULONG Attributes,
490 MEMORY_AREA** Result,
491 BOOL FixedAddress,
492 BOOL TopDown,
493 PHYSICAL_ADDRESS BoundaryAddressMultiple)
494 /*
495 * FUNCTION: Create a memory area
496 * ARGUMENTS:
497 * AddressSpace = Address space to create the area in
498 * Type = Type of the address space
499 * BaseAddress =
500 * Length = Length to allocate
501 * Attributes = Protection attributes for the memory area
502 * Result = Receives a pointer to the memory area on exit
503 * RETURNS: Status
504 * NOTES: Lock the address space before calling this function
505 */
506 {
507 PVOID EndAddress;
508 ULONG tmpLength;
509 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
510 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
511 Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
512
513 if ((*BaseAddress) == 0 && !FixedAddress)
514 {
515 tmpLength = PAGE_ROUND_UP(Length);
516 *BaseAddress = MmFindGap(AddressSpace,
517 PAGE_ROUND_UP(Length) +(PAGE_SIZE*2),
518 TopDown);
519 if ((*BaseAddress) == 0)
520 {
521 DPRINT("No suitable gap\n");
522 return(STATUS_NO_MEMORY);
523 }
524 #if defined(__GNUC__)
525 (*BaseAddress)=(*BaseAddress)+PAGE_SIZE;
526 #else
527
528 {
529 char* pTemp = *BaseAddress;
530 pTemp += PAGE_SIZE;
531 *BaseAddress = pTemp;
532 }
533 #endif
534
535 }
536 else
537 {
538 tmpLength = (ULONG)*BaseAddress + Length - PAGE_ROUND_DOWN((*BaseAddress));
539 (*BaseAddress) = (PVOID)PAGE_ROUND_DOWN((*BaseAddress));
540
541 if (AddressSpace->LowestAddress == KERNEL_BASE &&
542 (*BaseAddress) < (PVOID)KERNEL_BASE)
543 {
544 return STATUS_ACCESS_VIOLATION;
545 }
546
547 if (AddressSpace->LowestAddress < KERNEL_BASE &&
548 (PVOID)((char*)(*BaseAddress) + tmpLength) > (PVOID)KERNEL_BASE)
549 {
550 return STATUS_ACCESS_VIOLATION;
551 }
552
553 if (BoundaryAddressMultiple.QuadPart != 0)
554 {
555 EndAddress = ((char*)(*BaseAddress)) + tmpLength-1;
556 assert(((DWORD_PTR)*BaseAddress/BoundaryAddressMultiple.QuadPart) == ((DWORD_PTR)EndAddress/BoundaryAddressMultiple.QuadPart));
557 }
558
559 if (MmOpenMemoryAreaByRegion(AddressSpace,
560 *BaseAddress,
561 tmpLength)!=NULL)
562 {
563 DPRINT("Memory area already occupied\n");
564 return(STATUS_CONFLICTING_ADDRESSES);
565 }
566 }
567
568 *Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
569 TAG_MAREA);
570 RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
571 (*Result)->Type = Type;
572 (*Result)->BaseAddress = *BaseAddress;
573 (*Result)->Length = tmpLength;
574 (*Result)->Attributes = Attributes;
575 (*Result)->LockCount = 0;
576 (*Result)->Process = Process;
577 (*Result)->PageOpCount = 0;
578 (*Result)->DeleteInProgress = FALSE;
579
580 MmInsertMemoryArea(AddressSpace, *Result);
581
582 DPRINT("MmCreateMemoryArea() succeeded\n");
583 return(STATUS_SUCCESS);
584 }