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
+ 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
379 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
380 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
381 Type
,BaseAddress
,*BaseAddress
,Length
,Attributes
,Result
);
383 if ((*BaseAddress
)==0 && !FixedAddress
)
385 *BaseAddress
= MmFindGap(AddressSpace
,
386 PAGE_ROUND_UP(Length
) +(PAGE_SIZE
*2));
387 if ((*BaseAddress
)==0)
389 DPRINT("No suitable gap\n");
390 return(STATUS_NO_MEMORY
);
392 (*BaseAddress
)=(*BaseAddress
)+PAGE_SIZE
;
396 (*BaseAddress
) = (PVOID
)PAGE_ROUND_DOWN((*BaseAddress
));
397 if (MmOpenMemoryAreaByRegion(AddressSpace
,
401 DPRINT("Memory area already occupied\n");
402 return(STATUS_CONFLICTING_ADDRESSES
);
406 *Result
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MEMORY_AREA
),
408 RtlZeroMemory(*Result
,sizeof(MEMORY_AREA
));
409 (*Result
)->Type
= Type
;
410 (*Result
)->BaseAddress
= *BaseAddress
;
411 (*Result
)->Length
= Length
;
412 (*Result
)->Attributes
= Attributes
;
413 (*Result
)->LockCount
= 0;
414 (*Result
)->Process
= Process
;
415 (*Result
)->PageOpCount
= 0;
416 (*Result
)->DeleteInProgress
= FALSE
;
418 MmInsertMemoryArea(AddressSpace
, *Result
);
420 DPRINT("MmCreateMemoryArea() succeeded\n");
421 return(STATUS_SUCCESS
);