3 * Copyright (C) 1998, 1999, 2000, 2001 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);
208 PVOID MmFindGap(PMADDRESS_SPACE AddressSpace, ULONG Length)
210 PLIST_ENTRY ListHead;
211 PLIST_ENTRY current_entry;
212 MEMORY_AREA* current;
217 DPRINT("MmFindGap(Length %x)\n",Length);
219 ListHead = &AddressSpace->MAreaListHead;
221 current_entry = ListHead->Flink;
222 while (current_entry->Flink!=ListHead)
224 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
225 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
226 Gap = next->BaseAddress - (current->BaseAddress + PAGE_ROUND_UP(current->Length));
229 return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
231 current_entry = current_entry->Flink;
234 if (current_entry == ListHead)
236 Address = (PVOID)AddressSpace->LowestAddress;
240 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
241 Address = current->BaseAddress + PAGE_ROUND_UP(current->Length);
243 /* Check if enough space for the block */
244 if (AddressSpace->LowestAddress < KERNEL_BASE)
246 if ((ULONG)Address >= KERNEL_BASE || Length > KERNEL_BASE - (ULONG)Address)
253 if (Length >= 0xFFFFFFFF - (ULONG)Address)
261 NTSTATUS MmInitMemoryAreas(VOID)
263 * FUNCTION: Initialize the memory area list
266 DPRINT("MmInitMemoryAreas()\n",0);
267 return(STATUS_SUCCESS);
271 MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace,
274 VOID (*FreePage)(PVOID Context, MEMORY_AREA* MemoryArea,
275 PVOID Address, PHYSICAL_ADDRESS PhysAddr,
276 SWAPENTRY SwapEntry, BOOLEAN Dirty),
277 PVOID FreePageContext)
279 MEMORY_AREA* MemoryArea;
282 DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
283 "FreePageContext %d)\n",AddressSpace,BaseAddress,Length,
286 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
288 if (MemoryArea == NULL)
291 return(STATUS_UNSUCCESSFUL);
293 for (i=0; i<(PAGE_ROUND_UP(MemoryArea->Length)/PAGE_SIZE); i++)
295 PHYSICAL_ADDRESS PhysAddr = (PHYSICAL_ADDRESS)0LL;
297 SWAPENTRY SwapEntry = 0;
299 if (MmIsPageSwapEntry(AddressSpace->Process,
300 MemoryArea->BaseAddress + (i * PAGE_SIZE)))
302 MmDeletePageFileMapping(AddressSpace->Process,
303 MemoryArea->BaseAddress + (i * PAGE_SIZE),
308 MmDeleteVirtualMapping(AddressSpace->Process,
309 MemoryArea->BaseAddress + (i*PAGE_SIZE),
310 FALSE, &Dirty, &PhysAddr);
312 if (FreePage != NULL)
314 FreePage(FreePageContext, MemoryArea,
315 MemoryArea->BaseAddress + (i * PAGE_SIZE), PhysAddr,
320 RemoveEntryList(&MemoryArea->Entry);
321 ExFreePool(MemoryArea);
323 DPRINT("MmFreeMemoryArea() succeeded\n");
325 return(STATUS_SUCCESS);
328 PMEMORY_AREA MmSplitMemoryArea(PEPROCESS Process,
329 PMADDRESS_SPACE AddressSpace,
330 PMEMORY_AREA OriginalMemoryArea,
339 Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
341 RtlZeroMemory(Result,sizeof(MEMORY_AREA));
342 Result->Type = NewType;
343 Result->BaseAddress = BaseAddress;
344 Result->Length = Length;
345 Result->Attributes = NewAttributes;
346 Result->LockCount = 0;
347 Result->Process = Process;
349 if (BaseAddress == OriginalMemoryArea->BaseAddress)
351 OriginalMemoryArea->BaseAddress = BaseAddress + Length;
352 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
353 MmInsertMemoryArea(AddressSpace, Result);
356 if ((BaseAddress + Length) ==
357 (OriginalMemoryArea->BaseAddress + OriginalMemoryArea->Length))
359 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
360 MmInsertMemoryArea(AddressSpace, Result);
365 Split = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
367 RtlCopyMemory(Split,OriginalMemoryArea,sizeof(MEMORY_AREA));
368 Split->BaseAddress = BaseAddress + Length;
369 Split->Length = OriginalMemoryArea->Length - (((ULONG)BaseAddress)
372 OriginalMemoryArea->Length = BaseAddress - OriginalMemoryArea->BaseAddress;
377 NTSTATUS MmCreateMemoryArea(PEPROCESS Process,
378 PMADDRESS_SPACE AddressSpace,
383 MEMORY_AREA** Result,
386 * FUNCTION: Create a memory area
388 * AddressSpace = Address space to create the area in
389 * Type = Type of the address space
391 * Length = Length to allocate
392 * Attributes = Protection attributes for the memory area
393 * Result = Receives a pointer to the memory area on exit
395 * NOTES: Lock the address space before calling this function
399 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
400 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
401 Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
403 if ((*BaseAddress)==0 && !FixedAddress)
405 tmpLength = PAGE_ROUND_UP(Length);
406 *BaseAddress = MmFindGap(AddressSpace,
407 PAGE_ROUND_UP(Length) +(PAGE_SIZE*2));
408 if ((*BaseAddress)==0)
410 DPRINT("No suitable gap\n");
411 return(STATUS_NO_MEMORY);
413 (*BaseAddress)=(*BaseAddress)+PAGE_SIZE;
417 tmpLength = (ULONG)*BaseAddress + Length - PAGE_ROUND_DOWN((*BaseAddress));
418 (*BaseAddress) = (PVOID)PAGE_ROUND_DOWN((*BaseAddress));
419 if (MmOpenMemoryAreaByRegion(AddressSpace,
423 DPRINT("Memory area already occupied\n");
424 return(STATUS_CONFLICTING_ADDRESSES);
428 *Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
430 RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
431 (*Result)->Type = Type;
432 (*Result)->BaseAddress = *BaseAddress;
433 (*Result)->Length = tmpLength;
434 (*Result)->Attributes = Attributes;
435 (*Result)->LockCount = 0;
436 (*Result)->Process = Process;
437 (*Result)->PageOpCount = 0;
438 (*Result)->DeleteInProgress = FALSE;
440 MmInsertMemoryArea(AddressSpace, *Result);
442 DPRINT("MmCreateMemoryArea() succeeded\n");
443 return(STATUS_SUCCESS);