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;
216 DPRINT("MmFindGap(Length %x)\n",Length);
218 ListHead = &AddressSpace->MAreaListHead;
220 current_entry = ListHead->Flink;
221 while (current_entry->Flink!=ListHead)
223 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
224 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
225 Gap = next->BaseAddress - (current->BaseAddress + PAGE_ROUND_UP(current->Length));
228 return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
230 current_entry = current_entry->Flink;
233 if (current_entry == ListHead)
235 return((PVOID)AddressSpace->LowestAddress);
238 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
239 return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
242 NTSTATUS MmInitMemoryAreas(VOID)
244 * FUNCTION: Initialize the memory area list
247 DPRINT("MmInitMemoryAreas()\n",0);
248 return(STATUS_SUCCESS);
252 MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace,
255 VOID (*FreePage)(PVOID Context, MEMORY_AREA* MemoryArea,
256 PVOID Address, PHYSICAL_ADDRESS PhysAddr,
257 SWAPENTRY SwapEntry, BOOLEAN Dirty),
258 PVOID FreePageContext)
260 MEMORY_AREA* MemoryArea;
263 DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
264 "FreePageContext %d)\n",AddressSpace,BaseAddress,Length,
267 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
269 if (MemoryArea == NULL)
272 return(STATUS_UNSUCCESSFUL);
274 for (i=0; i<(PAGE_ROUND_UP(MemoryArea->Length)/PAGE_SIZE); i++)
276 PHYSICAL_ADDRESS PhysAddr = (PHYSICAL_ADDRESS)0LL;
278 SWAPENTRY SwapEntry = 0;
280 if (MmIsPageSwapEntry(AddressSpace->Process,
281 MemoryArea->BaseAddress + (i * PAGE_SIZE)))
283 MmDeletePageFileMapping(AddressSpace->Process,
284 MemoryArea->BaseAddress + (i * PAGE_SIZE),
289 MmDeleteVirtualMapping(AddressSpace->Process,
290 MemoryArea->BaseAddress + (i*PAGE_SIZE),
291 FALSE, &Dirty, &PhysAddr);
293 if (FreePage != NULL)
295 FreePage(FreePageContext, MemoryArea,
296 MemoryArea->BaseAddress + (i * PAGE_SIZE), PhysAddr,
301 RemoveEntryList(&MemoryArea->Entry);
302 ExFreePool(MemoryArea);
304 DPRINT("MmFreeMemoryArea() succeeded\n");
306 return(STATUS_SUCCESS);
309 PMEMORY_AREA MmSplitMemoryArea(PEPROCESS Process,
310 PMADDRESS_SPACE AddressSpace,
311 PMEMORY_AREA OriginalMemoryArea,
320 Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
322 RtlZeroMemory(Result,sizeof(MEMORY_AREA));
323 Result->Type = NewType;
324 Result->BaseAddress = BaseAddress;
325 Result->Length = Length;
326 Result->Attributes = NewAttributes;
327 Result->LockCount = 0;
328 Result->Process = Process;
330 if (BaseAddress == OriginalMemoryArea->BaseAddress)
332 OriginalMemoryArea->BaseAddress = BaseAddress + Length;
333 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
334 MmInsertMemoryArea(AddressSpace, Result);
337 if ((BaseAddress + Length) ==
338 (OriginalMemoryArea->BaseAddress + OriginalMemoryArea->Length))
340 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
341 MmInsertMemoryArea(AddressSpace, Result);
346 Split = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
348 RtlCopyMemory(Split,OriginalMemoryArea,sizeof(MEMORY_AREA));
349 Split->BaseAddress = BaseAddress + Length;
350 Split->Length = OriginalMemoryArea->Length - (((ULONG)BaseAddress)
353 OriginalMemoryArea->Length = BaseAddress - OriginalMemoryArea->BaseAddress;
358 NTSTATUS MmCreateMemoryArea(PEPROCESS Process,
359 PMADDRESS_SPACE AddressSpace,
364 MEMORY_AREA** Result,
367 * FUNCTION: Create a memory area
369 * AddressSpace = Address space to create the area in
370 * Type = Type of the address space
372 * Length = Length to allocate
373 * Attributes = Protection attributes for the memory area
374 * Result = Receives a pointer to the memory area on exit
376 * NOTES: Lock the address space before calling this function
380 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
381 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
382 Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
384 if ((*BaseAddress)==0 && !FixedAddress)
386 tmpLength = PAGE_ROUND_UP(Length);
387 *BaseAddress = MmFindGap(AddressSpace,
388 PAGE_ROUND_UP(Length) +(PAGE_SIZE*2));
389 if ((*BaseAddress)==0)
391 DPRINT("No suitable gap\n");
392 return(STATUS_NO_MEMORY);
394 (*BaseAddress)=(*BaseAddress)+PAGE_SIZE;
398 tmpLength = (ULONG)*BaseAddress + Length - PAGE_ROUND_DOWN((*BaseAddress));
399 (*BaseAddress) = (PVOID)PAGE_ROUND_DOWN((*BaseAddress));
400 if (MmOpenMemoryAreaByRegion(AddressSpace,
404 DPRINT("Memory area already occupied\n");
405 return(STATUS_CONFLICTING_ADDRESSES);
409 *Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
411 RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
412 (*Result)->Type = Type;
413 (*Result)->BaseAddress = *BaseAddress;
414 (*Result)->Length = tmpLength;
415 (*Result)->Attributes = Attributes;
416 (*Result)->LockCount = 0;
417 (*Result)->Process = Process;
418 (*Result)->PageOpCount = 0;
419 (*Result)->DeleteInProgress = FALSE;
421 MmInsertMemoryArea(AddressSpace, *Result);
423 DPRINT("MmCreateMemoryArea() succeeded\n");
424 return(STATUS_SUCCESS);