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 (char*)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 (PVOID
)((char*)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
< (PVOID
)((char*)Address
+Length
))
124 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
128 Extent
= (ULONG
)current
->BaseAddress
+ current
->Length
;
129 if (Extent
> (ULONG
)Address
&&
130 Extent
< (ULONG
)((char*)Address
+Length
))
132 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
136 if (current
->BaseAddress
<= Address
&&
137 Extent
>= (ULONG
)((char*)Address
+Length
))
139 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
143 if (current
->BaseAddress
>= (PVOID
)((char*)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
= (char*)next
->BaseAddress
- ((char*)current
->BaseAddress
+ PAGE_ROUND_UP(current
->Length
));
230 return((char*)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
= (char*)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
= (char*)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
= (char*)TopAddress
- (char*)BottomAddress
+ 1;
298 DPRINT("Bottom %p Top %p Gap %lx\n", BottomAddress
, TopAddress
, Gap
);
301 DPRINT("Found gap at %p\n", (char*)TopAddress
- Length
);
302 return((char*)TopAddress
- Length
+ 1);
304 TopAddress
= (char*)current
->BaseAddress
- 1;
306 current_entry
= current_entry
->Blink
;
309 if (current_entry
== ListHead
)
311 Address
= (char*)HighestAddress
- Length
+ 1;
315 Address
= (char*)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 INIT_FUNCTION
351 MmInitMemoryAreas(VOID
)
353 * FUNCTION: Initialize the memory area list
356 DPRINT("MmInitMemoryAreas()\n",0);
357 return(STATUS_SUCCESS
);
361 MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace
,
364 VOID (*FreePage
)(PVOID Context
, MEMORY_AREA
* MemoryArea
,
365 PVOID Address
, PHYSICAL_ADDRESS PhysAddr
,
366 SWAPENTRY SwapEntry
, BOOLEAN Dirty
),
367 PVOID FreePageContext
)
369 MEMORY_AREA
* MemoryArea
;
371 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
373 DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
374 "FreePageContext %d)\n",AddressSpace
,BaseAddress
,Length
,
377 MemoryArea
= MmOpenMemoryAreaByAddress(AddressSpace
,
379 if (MemoryArea
== NULL
)
382 return(STATUS_UNSUCCESSFUL
);
384 if (AddressSpace
->Process
!= NULL
&&
385 AddressSpace
->Process
!= CurrentProcess
)
387 KeAttachProcess(AddressSpace
->Process
);
389 for (i
=0; i
<(PAGE_ROUND_UP(MemoryArea
->Length
)/PAGE_SIZE
); i
++)
391 #if defined(__GNUC__)
392 PHYSICAL_ADDRESS PhysAddr
= (PHYSICAL_ADDRESS
)0LL;
395 PHYSICAL_ADDRESS PhysAddr
= { 0 };
399 SWAPENTRY SwapEntry
= 0;
401 if (MmIsPageSwapEntry(AddressSpace
->Process
,
402 (char*)MemoryArea
->BaseAddress
+ (i
* PAGE_SIZE
)))
404 MmDeletePageFileMapping(AddressSpace
->Process
,
405 (char*)MemoryArea
->BaseAddress
+ (i
* PAGE_SIZE
),
410 MmDeleteVirtualMapping(AddressSpace
->Process
,
411 (char*)MemoryArea
->BaseAddress
+ (i
*PAGE_SIZE
),
412 FALSE
, &Dirty
, &PhysAddr
);
415 if (FreePage
!= NULL
)
417 FreePage(FreePageContext
, MemoryArea
,
418 (char*)MemoryArea
->BaseAddress
+ (i
* PAGE_SIZE
), PhysAddr
,
419 SwapEntry
, (BOOLEAN
)Dirty
);
422 if (AddressSpace
->Process
!= NULL
&&
423 AddressSpace
->Process
!= CurrentProcess
)
427 RemoveEntryList(&MemoryArea
->Entry
);
428 ExFreePool(MemoryArea
);
430 DPRINT("MmFreeMemoryArea() succeeded\n");
432 return(STATUS_SUCCESS
);
435 PMEMORY_AREA
MmSplitMemoryArea(PEPROCESS Process
,
436 PMADDRESS_SPACE AddressSpace
,
437 PMEMORY_AREA OriginalMemoryArea
,
446 Result
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MEMORY_AREA
),
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
;
456 if (BaseAddress
== OriginalMemoryArea
->BaseAddress
)
458 OriginalMemoryArea
->BaseAddress
= (char*)BaseAddress
+ Length
;
459 OriginalMemoryArea
->Length
= OriginalMemoryArea
->Length
- Length
;
460 MmInsertMemoryArea(AddressSpace
, Result
);
463 if (((char*)BaseAddress
+ Length
) ==
464 ((char*)OriginalMemoryArea
->BaseAddress
+ OriginalMemoryArea
->Length
))
466 OriginalMemoryArea
->Length
= OriginalMemoryArea
->Length
- Length
;
467 MmInsertMemoryArea(AddressSpace
, Result
);
472 Split
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MEMORY_AREA
),
474 RtlCopyMemory(Split
,OriginalMemoryArea
,sizeof(MEMORY_AREA
));
475 Split
->BaseAddress
= (char*)BaseAddress
+ Length
;
476 Split
->Length
= OriginalMemoryArea
->Length
- (((ULONG
)BaseAddress
)
479 OriginalMemoryArea
->Length
= (char*)BaseAddress
- (char*)OriginalMemoryArea
->BaseAddress
;
484 NTSTATUS
MmCreateMemoryArea(PEPROCESS Process
,
485 PMADDRESS_SPACE AddressSpace
,
490 MEMORY_AREA
** Result
,
493 PHYSICAL_ADDRESS BoundaryAddressMultiple
)
495 * FUNCTION: Create a memory area
497 * AddressSpace = Address space to create the area in
498 * Type = Type of the address space
500 * Length = Length to allocate
501 * Attributes = Protection attributes for the memory area
502 * Result = Receives a pointer to the memory area on exit
504 * NOTES: Lock the address space before calling this function
509 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
510 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
511 Type
,BaseAddress
,*BaseAddress
,Length
,Attributes
,Result
);
513 if ((*BaseAddress
) == 0 && !FixedAddress
)
515 tmpLength
= PAGE_ROUND_UP(Length
);
516 *BaseAddress
= MmFindGap(AddressSpace
,
517 PAGE_ROUND_UP(Length
) +(PAGE_SIZE
*2),
519 if ((*BaseAddress
) == 0)
521 DPRINT("No suitable gap\n");
522 return(STATUS_NO_MEMORY
);
524 #if defined(__GNUC__)
525 (*BaseAddress
)=(*BaseAddress
)+PAGE_SIZE
;
529 char* pTemp
= *BaseAddress
;
531 *BaseAddress
= pTemp
;
538 tmpLength
= (ULONG
)*BaseAddress
+ Length
- PAGE_ROUND_DOWN((*BaseAddress
));
539 (*BaseAddress
) = (PVOID
)PAGE_ROUND_DOWN((*BaseAddress
));
541 if (AddressSpace
->LowestAddress
== KERNEL_BASE
&&
542 (*BaseAddress
) < (PVOID
)KERNEL_BASE
)
544 return STATUS_ACCESS_VIOLATION
;
547 if (AddressSpace
->LowestAddress
< KERNEL_BASE
&&
548 (PVOID
)((char*)(*BaseAddress
) + tmpLength
) > (PVOID
)KERNEL_BASE
)
550 return STATUS_ACCESS_VIOLATION
;
553 if (BoundaryAddressMultiple
.QuadPart
!= 0)
555 EndAddress
= ((char*)(*BaseAddress
)) + tmpLength
-1;
556 assert(((DWORD_PTR
)*BaseAddress
/BoundaryAddressMultiple
.QuadPart
) == ((DWORD_PTR
)EndAddress
/BoundaryAddressMultiple
.QuadPart
));
559 if (MmOpenMemoryAreaByRegion(AddressSpace
,
563 DPRINT("Memory area already occupied\n");
564 return(STATUS_CONFLICTING_ADDRESSES
);
568 *Result
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MEMORY_AREA
),
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
;
580 MmInsertMemoryArea(AddressSpace
, *Result
);
582 DPRINT("MmCreateMemoryArea() succeeded\n");
583 return(STATUS_SUCCESS
);