3 * Copyright (C) 1998, 1999, 2000, 2001, 2003 ReactOS Team
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.
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.
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.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/marea.c
22 * PURPOSE: Implements memory areas
23 * PROGRAMMER: David Welch (welch@mcmail.com)
28 /* INCLUDES *****************************************************************/
30 #include <ddk/ntddk.h>
31 #include <internal/mm.h>
32 #include <internal/ps.h>
33 #include <internal/pool.h>
36 #include <internal/debug.h>
38 /* GLOBALS *******************************************************************/
40 #define TAG_MAREA TAG('M', 'A', 'R', 'E')
42 /* FUNCTIONS *****************************************************************/
44 VOID MmDumpMemoryAreas(PLIST_ENTRY ListHead)
46 PLIST_ENTRY current_entry;
49 DbgPrint("MmDumpMemoryAreas()\n");
51 current_entry = ListHead->Flink;
52 while (current_entry!=ListHead)
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;
61 DbgPrint("Finished MmDumpMemoryAreas()\n");
64 MEMORY_AREA* MmOpenMemoryAreaByAddress(PMADDRESS_SPACE AddressSpace,
67 PLIST_ENTRY current_entry;
69 PLIST_ENTRY previous_entry;
71 DPRINT("MmOpenMemoryAreaByAddress(AddressSpace %x, Address %x)\n",
72 AddressSpace, Address);
74 previous_entry = &AddressSpace->MAreaListHead;
75 current_entry = AddressSpace->MAreaListHead.Flink;
76 while (current_entry != &AddressSpace->MAreaListHead)
78 current = CONTAINING_RECORD(current_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 (current->BaseAddress + current->Length) > Address)
87 DPRINT("%s() = %x\n",__FUNCTION__,current);
90 if (current->BaseAddress > Address)
92 DPRINT("%s() = NULL\n",__FUNCTION__);
95 previous_entry = current_entry;
96 current_entry = current_entry->Flink;
98 DPRINT("%s() = NULL\n",__FUNCTION__);
102 MEMORY_AREA* MmOpenMemoryAreaByRegion(PMADDRESS_SPACE AddressSpace,
106 PLIST_ENTRY current_entry;
107 MEMORY_AREA* current;
110 DPRINT("MmOpenMemoryByRegion(AddressSpace %x, Address %x, Length %x)\n",
111 AddressSpace, Address, Length);
113 current_entry = AddressSpace->MAreaListHead.Flink;
114 while (current_entry != &AddressSpace->MAreaListHead)
116 current = CONTAINING_RECORD(current_entry,
119 DPRINT("current->BaseAddress %x current->Length %x\n",
120 current->BaseAddress,current->Length);
121 if (current->BaseAddress >= Address &&
122 current->BaseAddress < (Address+Length))
124 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
128 Extent = (ULONG)current->BaseAddress + current->Length;
129 if (Extent > (ULONG)Address &&
130 Extent < (ULONG)(Address+Length))
132 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
136 if (current->BaseAddress <= Address &&
137 Extent >= (ULONG)(Address+Length))
139 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
143 if (current->BaseAddress >= (Address+Length))
145 DPRINT("Finished MmOpenMemoryAreaByRegion()= NULL\n",0);
148 current_entry = current_entry->Flink;
150 DPRINT("Finished MmOpenMemoryAreaByRegion() = NULL\n",0);
154 static VOID MmInsertMemoryArea(PMADDRESS_SPACE AddressSpace,
157 PLIST_ENTRY ListHead;
158 PLIST_ENTRY current_entry;
159 PLIST_ENTRY inserted_entry = &marea->Entry;
160 MEMORY_AREA* current;
163 DPRINT("MmInsertMemoryArea(marea %x)\n", marea);
164 DPRINT("marea->BaseAddress %x\n", marea->BaseAddress);
165 DPRINT("marea->Length %x\n", marea->Length);
167 ListHead = &AddressSpace->MAreaListHead;
169 current_entry = ListHead->Flink;
170 if (IsListEmpty(ListHead))
172 InsertHeadList(ListHead,&marea->Entry);
175 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
176 if (current->BaseAddress > marea->BaseAddress)
178 InsertHeadList(ListHead,&marea->Entry);
181 while (current_entry->Flink!=ListHead)
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)
188 current_entry->Flink = inserted_entry;
189 inserted_entry->Flink=ListHead;
190 inserted_entry->Blink=current_entry;
191 ListHead->Blink = inserted_entry;
194 if (current->BaseAddress < marea->BaseAddress &&
195 next->BaseAddress > marea->BaseAddress)
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;
203 current_entry = current_entry->Flink;
205 InsertTailList(ListHead,inserted_entry);
209 PVOID MmFindGapBottomUp(PMADDRESS_SPACE AddressSpace, ULONG Length)
211 PLIST_ENTRY ListHead;
212 PLIST_ENTRY current_entry;
213 MEMORY_AREA* current;
218 DPRINT("MmFindGapBottomUp(Length %x)\n",Length);
220 ListHead = &AddressSpace->MAreaListHead;
222 current_entry = ListHead->Flink;
223 while (current_entry->Flink!=ListHead)
225 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
226 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
227 Gap = next->BaseAddress - (current->BaseAddress + PAGE_ROUND_UP(current->Length));
230 return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
232 current_entry = current_entry->Flink;
235 if (current_entry == ListHead)
237 Address = (PVOID)AddressSpace->LowestAddress;
241 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
242 Address = current->BaseAddress + PAGE_ROUND_UP(current->Length);
244 /* Check if enough space for the block */
245 if (AddressSpace->LowestAddress < KERNEL_BASE)
247 if ((ULONG)Address >= KERNEL_BASE || Length > KERNEL_BASE - (ULONG)Address)
254 if (Length >= 0xFFFFFFFF - (ULONG)Address)
263 PVOID MmFindGapTopDown(PMADDRESS_SPACE AddressSpace, ULONG Length)
265 PLIST_ENTRY ListHead;
266 PLIST_ENTRY current_entry;
267 MEMORY_AREA* current;
272 PVOID HighestAddress;
274 DPRINT("MmFindGapTopDown(Length %lx)\n",Length);
276 if (AddressSpace->LowestAddress < KERNEL_BASE) //(ULONG_PTR)MmSystemRangeStart)
278 HighestAddress = MmHighestUserAddress;
282 HighestAddress = (PVOID)0xFFFFFFFF;
285 TopAddress = HighestAddress;
287 ListHead = &AddressSpace->MAreaListHead;
288 current_entry = ListHead->Blink;
289 while (current_entry->Blink != ListHead)
291 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
292 BottomAddress = current->BaseAddress + PAGE_ROUND_UP(current->Length);
293 DPRINT("Base %p Length %lx\n", current->BaseAddress, PAGE_ROUND_UP(current->Length));
295 if (BottomAddress < HighestAddress)
297 Gap = TopAddress - BottomAddress + 1;
298 DPRINT("Bottom %p Top %p Gap %lx\n", BottomAddress, TopAddress, Gap);
301 DPRINT("Found gap at %p\n", TopAddress - Length);
302 return(TopAddress - Length + 1);
304 TopAddress = current->BaseAddress - 1;
306 current_entry = current_entry->Blink;
309 if (current_entry == ListHead)
311 Address = (PVOID)HighestAddress - Length + 1;
315 Address = TopAddress - Length + 1;
318 /* Check if enough space for the block */
319 if (AddressSpace->LowestAddress < KERNEL_BASE)
321 if ((ULONG)Address >= KERNEL_BASE || Length > KERNEL_BASE - (ULONG)Address)
323 DPRINT("Failed to find gap\n");
329 if (Length >= 0xFFFFFFFF - (ULONG)Address)
331 DPRINT("Failed to find gap\n");
336 DPRINT("Found gap at %p\n", Address);
341 PVOID MmFindGap(PMADDRESS_SPACE AddressSpace, ULONG Length, BOOL TopDown)
344 return MmFindGapTopDown(AddressSpace, Length);
346 return MmFindGapBottomUp(AddressSpace, Length);
350 NTSTATUS MmInitMemoryAreas(VOID)
352 * FUNCTION: Initialize the memory area list
355 DPRINT("MmInitMemoryAreas()\n",0);
356 return(STATUS_SUCCESS);
360 MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace,
363 VOID (*FreePage)(PVOID Context, MEMORY_AREA* MemoryArea,
364 PVOID Address, PHYSICAL_ADDRESS PhysAddr,
365 SWAPENTRY SwapEntry, BOOLEAN Dirty),
366 PVOID FreePageContext)
368 MEMORY_AREA* MemoryArea;
370 PEPROCESS CurrentProcess = PsGetCurrentProcess();
372 DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
373 "FreePageContext %d)\n",AddressSpace,BaseAddress,Length,
376 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
378 if (MemoryArea == NULL)
381 return(STATUS_UNSUCCESSFUL);
383 if (AddressSpace->Process != NULL &&
384 AddressSpace->Process != CurrentProcess)
386 KeAttachProcess(AddressSpace->Process);
388 for (i=0; i<(PAGE_ROUND_UP(MemoryArea->Length)/PAGE_SIZE); i++)
390 PHYSICAL_ADDRESS PhysAddr = (PHYSICAL_ADDRESS)0LL;
392 SWAPENTRY SwapEntry = 0;
394 if (MmIsPageSwapEntry(AddressSpace->Process,
395 MemoryArea->BaseAddress + (i * PAGE_SIZE)))
397 MmDeletePageFileMapping(AddressSpace->Process,
398 MemoryArea->BaseAddress + (i * PAGE_SIZE),
403 MmDeleteVirtualMapping(AddressSpace->Process,
404 MemoryArea->BaseAddress + (i*PAGE_SIZE),
405 FALSE, &Dirty, &PhysAddr);
408 if (FreePage != NULL)
410 FreePage(FreePageContext, MemoryArea,
411 MemoryArea->BaseAddress + (i * PAGE_SIZE), PhysAddr,
415 if (AddressSpace->Process != NULL &&
416 AddressSpace->Process != CurrentProcess)
420 RemoveEntryList(&MemoryArea->Entry);
421 ExFreePool(MemoryArea);
423 DPRINT("MmFreeMemoryArea() succeeded\n");
425 return(STATUS_SUCCESS);
428 PMEMORY_AREA MmSplitMemoryArea(PEPROCESS Process,
429 PMADDRESS_SPACE AddressSpace,
430 PMEMORY_AREA OriginalMemoryArea,
439 Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
441 RtlZeroMemory(Result,sizeof(MEMORY_AREA));
442 Result->Type = NewType;
443 Result->BaseAddress = BaseAddress;
444 Result->Length = Length;
445 Result->Attributes = NewAttributes;
446 Result->LockCount = 0;
447 Result->Process = Process;
449 if (BaseAddress == OriginalMemoryArea->BaseAddress)
451 OriginalMemoryArea->BaseAddress = BaseAddress + Length;
452 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
453 MmInsertMemoryArea(AddressSpace, Result);
456 if ((BaseAddress + Length) ==
457 (OriginalMemoryArea->BaseAddress + OriginalMemoryArea->Length))
459 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
460 MmInsertMemoryArea(AddressSpace, Result);
465 Split = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
467 RtlCopyMemory(Split,OriginalMemoryArea,sizeof(MEMORY_AREA));
468 Split->BaseAddress = BaseAddress + Length;
469 Split->Length = OriginalMemoryArea->Length - (((ULONG)BaseAddress)
472 OriginalMemoryArea->Length = BaseAddress - OriginalMemoryArea->BaseAddress;
477 NTSTATUS MmCreateMemoryArea(PEPROCESS Process,
478 PMADDRESS_SPACE AddressSpace,
483 MEMORY_AREA** Result,
487 * FUNCTION: Create a memory area
489 * AddressSpace = Address space to create the area in
490 * Type = Type of the address space
492 * Length = Length to allocate
493 * Attributes = Protection attributes for the memory area
494 * Result = Receives a pointer to the memory area on exit
496 * NOTES: Lock the address space before calling this function
500 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
501 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
502 Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
504 if ((*BaseAddress) == 0 && !FixedAddress)
506 tmpLength = PAGE_ROUND_UP(Length);
507 *BaseAddress = MmFindGap(AddressSpace,
508 PAGE_ROUND_UP(Length) +(PAGE_SIZE*2),
510 if ((*BaseAddress) == 0)
512 DPRINT("No suitable gap\n");
513 return(STATUS_NO_MEMORY);
515 (*BaseAddress)=(*BaseAddress)+PAGE_SIZE;
519 tmpLength = (ULONG)*BaseAddress + Length - PAGE_ROUND_DOWN((*BaseAddress));
520 (*BaseAddress) = (PVOID)PAGE_ROUND_DOWN((*BaseAddress));
521 if (MmOpenMemoryAreaByRegion(AddressSpace,
525 DPRINT("Memory area already occupied\n");
526 return(STATUS_CONFLICTING_ADDRESSES);
530 *Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
532 RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
533 (*Result)->Type = Type;
534 (*Result)->BaseAddress = *BaseAddress;
535 (*Result)->Length = tmpLength;
536 (*Result)->Attributes = Attributes;
537 (*Result)->LockCount = 0;
538 (*Result)->Process = Process;
539 (*Result)->PageOpCount = 0;
540 (*Result)->DeleteInProgress = FALSE;
542 MmInsertMemoryArea(AddressSpace, *Result);
544 DPRINT("MmCreateMemoryArea() succeeded\n");
545 return(STATUS_SUCCESS);