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 // MmDumpMemoryAreas(&AddressSpace->MAreaListHead);
76 previous_entry
= &AddressSpace
->MAreaListHead
;
77 current_entry
= AddressSpace
->MAreaListHead
.Flink
;
78 while (current_entry
!= &AddressSpace
->MAreaListHead
)
80 current
= CONTAINING_RECORD(current_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
)
88 DPRINT1("BaseAddress %x\n", current
->BaseAddress
);
89 DPRINT1("current_entry->Flink %x ", current_entry
->Flink
);
90 DPRINT1("¤t_entry->Flink %x\n",
91 ¤t_entry
->Flink
);
92 DPRINT1("current_entry->Flink->Blink %x\n",
93 current_entry
->Flink
->Blink
);
94 DPRINT1("¤t_entry->Flink->Blink %x\n",
95 ¤t_entry
->Flink
->Blink
);
96 DPRINT1("¤t_entry->Flink %x\n",
97 ¤t_entry
->Flink
);
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
)
104 DPRINT("%s() = %x\n",__FUNCTION__
,current
);
107 if (current
->BaseAddress
> Address
)
109 DPRINT("%s() = NULL\n",__FUNCTION__
);
112 previous_entry
= current_entry
;
113 current_entry
= current_entry
->Flink
;
115 DPRINT("%s() = NULL\n",__FUNCTION__
);
119 MEMORY_AREA
* MmOpenMemoryAreaByRegion(PMADDRESS_SPACE AddressSpace
,
123 PLIST_ENTRY current_entry
;
124 MEMORY_AREA
* current
;
127 DPRINT("MmOpenMemoryByRegion(AddressSpace %x, Address %x, Length %x)\n",
128 AddressSpace
, Address
, Length
);
130 current_entry
= AddressSpace
->MAreaListHead
.Flink
;
131 while (current_entry
!= &AddressSpace
->MAreaListHead
)
133 current
= CONTAINING_RECORD(current_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
))
141 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
145 Extent
= (ULONG
)current
->BaseAddress
+ current
->Length
;
146 if (Extent
> (ULONG
)Address
&&
147 Extent
< (ULONG
)(Address
+Length
))
149 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
153 if (current
->BaseAddress
<= Address
&&
154 Extent
>= (ULONG
)(Address
+Length
))
156 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
160 if (current
->BaseAddress
>= (Address
+Length
))
162 DPRINT("Finished MmOpenMemoryAreaByRegion()= NULL\n",0);
165 current_entry
= current_entry
->Flink
;
167 DPRINT("Finished MmOpenMemoryAreaByRegion() = NULL\n",0);
171 static VOID
MmInsertMemoryArea(PMADDRESS_SPACE AddressSpace
,
174 PLIST_ENTRY ListHead
;
175 PLIST_ENTRY current_entry
;
176 PLIST_ENTRY inserted_entry
= &marea
->Entry
;
177 MEMORY_AREA
* current
;
180 DPRINT("MmInsertMemoryArea(marea %x)\n", marea
);
181 DPRINT("marea->BaseAddress %x\n", marea
->BaseAddress
);
182 DPRINT("marea->Length %x\n", marea
->Length
);
184 ListHead
= &AddressSpace
->MAreaListHead
;
186 current_entry
= ListHead
->Flink
;
188 if (IsListEmpty(ListHead
))
191 InsertHeadList(ListHead
,&marea
->Entry
);
192 DPRINT("Inserting at list head\n");
197 current
= CONTAINING_RECORD(current_entry
,MEMORY_AREA
,Entry
);
199 if (current
->BaseAddress
> marea
->BaseAddress
)
202 InsertHeadList(ListHead
,&marea
->Entry
);
203 DPRINT("Inserting at list head\n");
208 while (current_entry
->Flink
!=ListHead
)
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
)
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
;
225 if (current
->BaseAddress
< marea
->BaseAddress
&&
226 next
->BaseAddress
> marea
->BaseAddress
)
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
;
235 current_entry
= current_entry
->Flink
;
238 DPRINT("Inserting at list tail\n");
239 InsertTailList(ListHead
,inserted_entry
);
242 static PVOID
MmFindGap(PMADDRESS_SPACE AddressSpace
,
245 PLIST_ENTRY ListHead
;
246 PLIST_ENTRY current_entry
;
247 MEMORY_AREA
* current
;
251 DPRINT("MmFindGap(Length %x)\n",Length
);
253 ListHead
= &AddressSpace
->MAreaListHead
;
255 current_entry
= ListHead
->Flink
;
256 while (current_entry
->Flink
!=ListHead
)
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
);
268 return(current
->BaseAddress
+ PAGE_ROUND_UP(current
->Length
));
270 current_entry
= current_entry
->Flink
;
273 if (current_entry
== ListHead
)
275 return((PVOID
)AddressSpace
->LowestAddress
);
278 current
= CONTAINING_RECORD(current_entry
,MEMORY_AREA
,Entry
);
279 //DbgPrint("current %x returning %x\n",current,current->BaseAddress+
281 return(current
->BaseAddress
+ PAGE_ROUND_UP(current
->Length
));
284 NTSTATUS
MmInitMemoryAreas(VOID
)
286 * FUNCTION: Initialize the memory area list
289 DPRINT("MmInitMemoryAreas()\n",0);
290 return(STATUS_SUCCESS
);
294 MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace
,
297 VOID (*FreePage
)(PVOID Context
, MEMORY_AREA
* MemoryArea
, PVOID Address
,
298 PHYSICAL_ADDRESS PhysAddr
, SWAPENTRY SwapEntry
, BOOLEAN Dirty
),
299 PVOID FreePageContext
)
301 MEMORY_AREA
* MemoryArea
;
304 DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
305 "FreePageContext %d)\n",AddressSpace
,BaseAddress
,Length
,FreePageContext
);
307 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
309 if (MemoryArea
== NULL
)
312 return(STATUS_UNSUCCESSFUL
);
314 for (i
=0; i
<(PAGE_ROUND_UP(MemoryArea
->Length
)/PAGESIZE
); i
++)
316 PHYSICAL_ADDRESS PhysAddr
= (PHYSICAL_ADDRESS
)0LL;
318 SWAPENTRY SwapEntry
= 0;
320 if (MmIsPageSwapEntry(AddressSpace
->Process
,
321 MemoryArea
->BaseAddress
+ (i
* PAGESIZE
)))
323 MmDeletePageFileMapping(AddressSpace
->Process
,
324 MemoryArea
->BaseAddress
+ (i
* PAGESIZE
),
329 MmDeleteVirtualMapping(AddressSpace
->Process
,
330 MemoryArea
->BaseAddress
+ (i
*PAGESIZE
),
331 FALSE
, &Dirty
, &PhysAddr
);
333 if (FreePage
!= NULL
)
335 FreePage(FreePageContext
, MemoryArea
,
336 MemoryArea
->BaseAddress
+ (i
* PAGESIZE
), PhysAddr
,
341 RemoveEntryList(&MemoryArea
->Entry
);
342 ExFreePool(MemoryArea
);
344 DPRINT("MmFreeMemoryArea() succeeded\n");
346 return(STATUS_SUCCESS
);
349 PMEMORY_AREA
MmSplitMemoryArea(PEPROCESS Process
,
350 PMADDRESS_SPACE AddressSpace
,
351 PMEMORY_AREA OriginalMemoryArea
,
360 Result
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MEMORY_AREA
),
362 RtlZeroMemory(Result
,sizeof(MEMORY_AREA
));
363 Result
->Type
= NewType
;
364 Result
->BaseAddress
= BaseAddress
;
365 Result
->Length
= Length
;
366 Result
->Attributes
= NewAttributes
;
367 Result
->LockCount
= 0;
368 Result
->Process
= Process
;
370 if (BaseAddress
== OriginalMemoryArea
->BaseAddress
)
372 OriginalMemoryArea
->BaseAddress
= BaseAddress
+ Length
;
373 OriginalMemoryArea
->Length
= OriginalMemoryArea
->Length
- Length
;
374 MmInsertMemoryArea(AddressSpace
, Result
);
377 if ((BaseAddress
+ Length
) ==
378 (OriginalMemoryArea
->BaseAddress
+ OriginalMemoryArea
->Length
))
380 OriginalMemoryArea
->Length
= OriginalMemoryArea
->Length
- Length
;
381 MmInsertMemoryArea(AddressSpace
, Result
);
386 Split
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MEMORY_AREA
),
388 RtlCopyMemory(Split
,OriginalMemoryArea
,sizeof(MEMORY_AREA
));
389 Split
->BaseAddress
= BaseAddress
+ Length
;
390 Split
->Length
= OriginalMemoryArea
->Length
- (((ULONG
)BaseAddress
)
393 OriginalMemoryArea
->Length
= BaseAddress
- OriginalMemoryArea
->BaseAddress
;
398 NTSTATUS
MmCreateMemoryArea(PEPROCESS Process
,
399 PMADDRESS_SPACE AddressSpace
,
404 MEMORY_AREA
** Result
,
407 * FUNCTION: Create a memory area
409 * AddressSpace = Address space to create the area in
410 * Type = Type of the address space
412 * Length = Length to allocate
413 * Attributes = Protection attributes for the memory area
414 * Result = Receives a pointer to the memory area on exit
416 * NOTES: Lock the address space before calling this function
419 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
420 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
421 Type
,BaseAddress
,*BaseAddress
,Length
,Attributes
,Result
);
423 if ((*BaseAddress
)==0 && !FixedAddress
)
425 *BaseAddress
= MmFindGap(AddressSpace
,
426 PAGE_ROUND_UP(Length
) +(PAGESIZE
*2));
427 if ((*BaseAddress
)==0)
429 DPRINT("No suitable gap\n");
430 return(STATUS_NO_MEMORY
);
432 (*BaseAddress
)=(*BaseAddress
)+PAGESIZE
;
436 (*BaseAddress
) = (PVOID
)PAGE_ROUND_DOWN((*BaseAddress
));
437 if (MmOpenMemoryAreaByRegion(AddressSpace
,
441 DPRINT("Memory area already occupied\n");
442 return(STATUS_CONFLICTING_ADDRESSES
);
446 *Result
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MEMORY_AREA
),
448 RtlZeroMemory(*Result
,sizeof(MEMORY_AREA
));
449 (*Result
)->Type
= Type
;
450 (*Result
)->BaseAddress
= *BaseAddress
;
451 (*Result
)->Length
= Length
;
452 (*Result
)->Attributes
= Attributes
;
453 (*Result
)->LockCount
= 0;
454 (*Result
)->Process
= Process
;
456 MmInsertMemoryArea(AddressSpace
, *Result
);
458 DPRINT("MmCreateMemoryArea() succeeded\n");
459 return(STATUS_SUCCESS
);