69ab18e8632f1564be47fc25ae930b2b28d9543f
[reactos.git] / reactos / ntoskrnl / mm / marea.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /*
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/marea.c
22 * PURPOSE: Implements memory areas
23 * PROGRAMMER: David Welch (welch@mcmail.com)
24 * UPDATE HISTORY:
25 * Created 22/05/98
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include <internal/mm.h>
32 #include <internal/ps.h>
33 #include <internal/pool.h>
34
35 #define NDEBUG
36 #include <internal/debug.h>
37
38 /* GLOBALS *******************************************************************/
39
40 #define TAG_MAREA TAG('M', 'A', 'R', 'E')
41
42 /* FUNCTIONS *****************************************************************/
43
44 VOID MmDumpMemoryAreas(PLIST_ENTRY ListHead)
45 {
46 PLIST_ENTRY current_entry;
47 MEMORY_AREA* current;
48
49 DbgPrint("MmDumpMemoryAreas()\n");
50
51 current_entry = ListHead->Flink;
52 while (current_entry!=ListHead)
53 {
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;
60 }
61 DbgPrint("Finished MmDumpMemoryAreas()\n");
62 }
63
64 MEMORY_AREA* MmOpenMemoryAreaByAddress(PMADDRESS_SPACE AddressSpace,
65 PVOID Address)
66 {
67 PLIST_ENTRY current_entry;
68 MEMORY_AREA* current;
69 PLIST_ENTRY previous_entry;
70
71 DPRINT("MmOpenMemoryAreaByAddress(AddressSpace %x, Address %x)\n",
72 AddressSpace, Address);
73
74 // MmDumpMemoryAreas(&AddressSpace->MAreaListHead);
75
76 previous_entry = &AddressSpace->MAreaListHead;
77 current_entry = AddressSpace->MAreaListHead.Flink;
78 while (current_entry != &AddressSpace->MAreaListHead)
79 {
80 current = CONTAINING_RECORD(current_entry,
81 MEMORY_AREA,
82 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)
87 {
88 DPRINT1("BaseAddress %x\n", current->BaseAddress);
89 DPRINT1("current_entry->Flink %x ", current_entry->Flink);
90 DPRINT1("&current_entry->Flink %x\n",
91 &current_entry->Flink);
92 DPRINT1("current_entry->Flink->Blink %x\n",
93 current_entry->Flink->Blink);
94 DPRINT1("&current_entry->Flink->Blink %x\n",
95 &current_entry->Flink->Blink);
96 DPRINT1("&current_entry->Flink %x\n",
97 &current_entry->Flink);
98 }
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)
103 {
104 DPRINT("%s() = %x\n",__FUNCTION__,current);
105 return(current);
106 }
107 if (current->BaseAddress > Address)
108 {
109 DPRINT("%s() = NULL\n",__FUNCTION__);
110 return(NULL);
111 }
112 previous_entry = current_entry;
113 current_entry = current_entry->Flink;
114 }
115 DPRINT("%s() = NULL\n",__FUNCTION__);
116 return(NULL);
117 }
118
119 MEMORY_AREA* MmOpenMemoryAreaByRegion(PMADDRESS_SPACE AddressSpace,
120 PVOID Address,
121 ULONG Length)
122 {
123 PLIST_ENTRY current_entry;
124 MEMORY_AREA* current;
125 ULONG Extent;
126
127 DPRINT("MmOpenMemoryByRegion(AddressSpace %x, Address %x, Length %x)\n",
128 AddressSpace, Address, Length);
129
130 current_entry = AddressSpace->MAreaListHead.Flink;
131 while (current_entry != &AddressSpace->MAreaListHead)
132 {
133 current = CONTAINING_RECORD(current_entry,
134 MEMORY_AREA,
135 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))
140 {
141 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
142 current);
143 return(current);
144 }
145 Extent = (ULONG)current->BaseAddress + current->Length;
146 if (Extent > (ULONG)Address &&
147 Extent < (ULONG)(Address+Length))
148 {
149 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
150 current);
151 return(current);
152 }
153 if (current->BaseAddress <= Address &&
154 Extent >= (ULONG)(Address+Length))
155 {
156 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
157 current);
158 return(current);
159 }
160 if (current->BaseAddress >= (Address+Length))
161 {
162 DPRINT("Finished MmOpenMemoryAreaByRegion()= NULL\n",0);
163 return(NULL);
164 }
165 current_entry = current_entry->Flink;
166 }
167 DPRINT("Finished MmOpenMemoryAreaByRegion() = NULL\n",0);
168 return(NULL);
169 }
170
171 static VOID MmInsertMemoryArea(PMADDRESS_SPACE AddressSpace,
172 MEMORY_AREA* marea)
173 {
174 PLIST_ENTRY ListHead;
175 PLIST_ENTRY current_entry;
176 PLIST_ENTRY inserted_entry = &marea->Entry;
177 MEMORY_AREA* current;
178 MEMORY_AREA* next;
179
180 DPRINT("MmInsertMemoryArea(marea %x)\n", marea);
181 DPRINT("marea->BaseAddress %x\n", marea->BaseAddress);
182 DPRINT("marea->Length %x\n", marea->Length);
183
184 ListHead = &AddressSpace->MAreaListHead;
185
186 current_entry = ListHead->Flink;
187 CHECKPOINT;
188 if (IsListEmpty(ListHead))
189 {
190 CHECKPOINT;
191 InsertHeadList(ListHead,&marea->Entry);
192 DPRINT("Inserting at list head\n");
193 CHECKPOINT;
194 return;
195 }
196 CHECKPOINT;
197 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
198 CHECKPOINT;
199 if (current->BaseAddress > marea->BaseAddress)
200 {
201 CHECKPOINT;
202 InsertHeadList(ListHead,&marea->Entry);
203 DPRINT("Inserting at list head\n");
204 CHECKPOINT;
205 return;
206 }
207 CHECKPOINT;
208 while (current_entry->Flink!=ListHead)
209 {
210 // CHECKPOINT;
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)
217 {
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;
223 return;
224 }
225 if (current->BaseAddress < marea->BaseAddress &&
226 next->BaseAddress > marea->BaseAddress)
227 {
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;
233 return;
234 }
235 current_entry = current_entry->Flink;
236 }
237 CHECKPOINT;
238 DPRINT("Inserting at list tail\n");
239 InsertTailList(ListHead,inserted_entry);
240 }
241
242 static PVOID MmFindGap(PMADDRESS_SPACE AddressSpace,
243 ULONG Length)
244 {
245 PLIST_ENTRY ListHead;
246 PLIST_ENTRY current_entry;
247 MEMORY_AREA* current;
248 MEMORY_AREA* next;
249 ULONG Gap;
250
251 DPRINT("MmFindGap(Length %x)\n",Length);
252
253 ListHead = &AddressSpace->MAreaListHead;
254
255 current_entry = ListHead->Flink;
256 while (current_entry->Flink!=ListHead)
257 {
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);
266 if (Gap >= Length)
267 {
268 return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
269 }
270 current_entry = current_entry->Flink;
271 }
272
273 if (current_entry == ListHead)
274 {
275 return((PVOID)AddressSpace->LowestAddress);
276 }
277
278 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
279 //DbgPrint("current %x returning %x\n",current,current->BaseAddress+
280 // current->Length);
281 return(current->BaseAddress + PAGE_ROUND_UP(current->Length));
282 }
283
284 NTSTATUS MmInitMemoryAreas(VOID)
285 /*
286 * FUNCTION: Initialize the memory area list
287 */
288 {
289 DPRINT("MmInitMemoryAreas()\n",0);
290 return(STATUS_SUCCESS);
291 }
292
293 NTSTATUS
294 MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace,
295 PVOID BaseAddress,
296 ULONG Length,
297 VOID (*FreePage)(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
298 ULONG PhysAddr, SWAPENTRY SwapEntry, BOOLEAN Dirty),
299 PVOID FreePageContext)
300 {
301 MEMORY_AREA* MemoryArea;
302 ULONG i;
303
304 DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
305 "FreePageContext %d)\n",AddressSpace,BaseAddress,Length,FreePageContext);
306
307 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
308 BaseAddress);
309 if (MemoryArea == NULL)
310 {
311 KeBugCheck(0);
312 return(STATUS_UNSUCCESSFUL);
313 }
314 for (i=0; i<(PAGE_ROUND_UP(MemoryArea->Length)/PAGESIZE); i++)
315 {
316 ULONG PhysAddr = 0;
317 BOOL Dirty;
318 SWAPENTRY SwapEntry = 0;
319
320 if (MmIsPageSwapEntry(AddressSpace->Process,
321 MemoryArea->BaseAddress + (i * PAGESIZE)))
322 {
323 MmDeletePageFileMapping(AddressSpace->Process,
324 MemoryArea->BaseAddress + (i * PAGESIZE),
325 &SwapEntry);
326 }
327 else
328 {
329 MmDeleteVirtualMapping(AddressSpace->Process,
330 MemoryArea->BaseAddress + (i*PAGESIZE),
331 FALSE, &Dirty, &PhysAddr);
332 }
333 if (FreePage != NULL)
334 {
335 FreePage(FreePageContext, MemoryArea,
336 MemoryArea->BaseAddress + (i * PAGESIZE), PhysAddr, SwapEntry, Dirty);
337 }
338 }
339
340 RemoveEntryList(&MemoryArea->Entry);
341 ExFreePool(MemoryArea);
342
343 DPRINT("MmFreeMemoryArea() succeeded\n");
344
345 return(STATUS_SUCCESS);
346 }
347
348 PMEMORY_AREA MmSplitMemoryArea(PEPROCESS Process,
349 PMADDRESS_SPACE AddressSpace,
350 PMEMORY_AREA OriginalMemoryArea,
351 PVOID BaseAddress,
352 ULONG Length,
353 ULONG NewType,
354 ULONG NewAttributes)
355 {
356 PMEMORY_AREA Result;
357 PMEMORY_AREA Split;
358
359 Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
360 TAG_MAREA);
361 RtlZeroMemory(Result,sizeof(MEMORY_AREA));
362 Result->Type = NewType;
363 Result->BaseAddress = BaseAddress;
364 Result->Length = Length;
365 Result->Attributes = NewAttributes;
366 Result->LockCount = 0;
367 Result->Process = Process;
368
369 if (BaseAddress == OriginalMemoryArea->BaseAddress)
370 {
371 OriginalMemoryArea->BaseAddress = BaseAddress + Length;
372 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
373 MmInsertMemoryArea(AddressSpace, Result);
374 return(Result);
375 }
376 if ((BaseAddress + Length) ==
377 (OriginalMemoryArea->BaseAddress + OriginalMemoryArea->Length))
378 {
379 OriginalMemoryArea->Length = OriginalMemoryArea->Length - Length;
380 MmInsertMemoryArea(AddressSpace, Result);
381
382 return(Result);
383 }
384
385 Split = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
386 TAG_MAREA);
387 RtlCopyMemory(Split,OriginalMemoryArea,sizeof(MEMORY_AREA));
388 Split->BaseAddress = BaseAddress + Length;
389 Split->Length = OriginalMemoryArea->Length - (((ULONG)BaseAddress)
390 + Length);
391
392 OriginalMemoryArea->Length = BaseAddress - OriginalMemoryArea->BaseAddress;
393
394 return(Split);
395 }
396
397 NTSTATUS MmCreateMemoryArea(PEPROCESS Process,
398 PMADDRESS_SPACE AddressSpace,
399 ULONG Type,
400 PVOID* BaseAddress,
401 ULONG Length,
402 ULONG Attributes,
403 MEMORY_AREA** Result,
404 BOOL FixedAddress)
405 /*
406 * FUNCTION: Create a memory area
407 * ARGUMENTS:
408 * AddressSpace = Address space to create the area in
409 * Type = Type of the address space
410 * BaseAddress =
411 * Length = Length to allocate
412 * Attributes = Protection attributes for the memory area
413 * Result = Receives a pointer to the memory area on exit
414 * RETURNS: Status
415 * NOTES: Lock the address space before calling this function
416 */
417 {
418 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
419 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
420 Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
421
422 if ((*BaseAddress)==0 && !FixedAddress)
423 {
424 *BaseAddress = MmFindGap(AddressSpace,
425 PAGE_ROUND_UP(Length) +(PAGESIZE*2));
426 if ((*BaseAddress)==0)
427 {
428 DPRINT("No suitable gap\n");
429 return(STATUS_NO_MEMORY);
430 }
431 (*BaseAddress)=(*BaseAddress)+PAGESIZE;
432 }
433 else
434 {
435 (*BaseAddress) = (PVOID)PAGE_ROUND_DOWN((*BaseAddress));
436 if (MmOpenMemoryAreaByRegion(AddressSpace,
437 *BaseAddress,
438 Length)!=NULL)
439 {
440 DPRINT("Memory area already occupied\n");
441 return(STATUS_CONFLICTING_ADDRESSES);
442 }
443 }
444
445 *Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
446 TAG_MAREA);
447 RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
448 (*Result)->Type = Type;
449 (*Result)->BaseAddress = *BaseAddress;
450 (*Result)->Length = Length;
451 (*Result)->Attributes = Attributes;
452 (*Result)->LockCount = 0;
453 (*Result)->Process = Process;
454
455 MmInsertMemoryArea(AddressSpace, *Result);
456
457 DPRINT("MmCreateMemoryArea() succeeded\n");
458 return(STATUS_SUCCESS);
459 }