- Remove unused and broken MmSplitMemoryArea function.
[reactos.git] / reactos / ntoskrnl / mm / marea.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001, 2003 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 <ntoskrnl.h>
31 #define NDEBUG
32 #include <internal/debug.h>
33
34 /* GLOBALS *******************************************************************/
35
36 #define TAG_MAREA TAG('M', 'A', 'R', 'E')
37
38 /* FUNCTIONS *****************************************************************/
39
40 VOID MmDumpMemoryAreas(PLIST_ENTRY ListHead)
41 {
42 PLIST_ENTRY current_entry;
43 MEMORY_AREA* current;
44
45 DbgPrint("MmDumpMemoryAreas()\n");
46
47 current_entry = ListHead->Flink;
48 while (current_entry!=ListHead)
49 {
50 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
51 DbgPrint("Base %x Length %x End %x Attributes %x Flink %x\n",
52 current->BaseAddress,current->Length,
53 (char*)current->BaseAddress+current->Length,current->Attributes,
54 current->Entry.Flink);
55 current_entry = current_entry->Flink;
56 }
57 DbgPrint("Finished MmDumpMemoryAreas()\n");
58 }
59
60 MEMORY_AREA* MmOpenMemoryAreaByAddress(PMADDRESS_SPACE AddressSpace,
61 PVOID Address)
62 {
63 PLIST_ENTRY current_entry;
64 MEMORY_AREA* current;
65 PLIST_ENTRY previous_entry;
66
67 DPRINT("MmOpenMemoryAreaByAddress(AddressSpace %x, Address %x)\n",
68 AddressSpace, Address);
69
70 previous_entry = &AddressSpace->MAreaListHead;
71 current_entry = AddressSpace->MAreaListHead.Flink;
72 while (current_entry != &AddressSpace->MAreaListHead)
73 {
74 current = CONTAINING_RECORD(current_entry,
75 MEMORY_AREA,
76 Entry);
77 ASSERT(current_entry->Blink->Flink == current_entry);
78 ASSERT(current_entry->Flink->Blink == current_entry);
79 ASSERT(previous_entry->Flink == current_entry);
80 if (current->BaseAddress <= Address &&
81 (PVOID)((char*)current->BaseAddress + current->Length) > Address)
82 {
83 DPRINT("%s() = %x\n",__FUNCTION__,current);
84 return(current);
85 }
86 if (current->BaseAddress > Address)
87 {
88 DPRINT("%s() = NULL\n",__FUNCTION__);
89 return(NULL);
90 }
91 previous_entry = current_entry;
92 current_entry = current_entry->Flink;
93 }
94 DPRINT("%s() = NULL\n",__FUNCTION__);
95 return(NULL);
96 }
97
98 MEMORY_AREA* MmOpenMemoryAreaByRegion(PMADDRESS_SPACE AddressSpace,
99 PVOID Address,
100 ULONG Length)
101 {
102 PLIST_ENTRY current_entry;
103 MEMORY_AREA* current;
104 ULONG Extent;
105
106 DPRINT("MmOpenMemoryByRegion(AddressSpace %x, Address %x, Length %x)\n",
107 AddressSpace, Address, Length);
108
109 current_entry = AddressSpace->MAreaListHead.Flink;
110 while (current_entry != &AddressSpace->MAreaListHead)
111 {
112 current = CONTAINING_RECORD(current_entry,
113 MEMORY_AREA,
114 Entry);
115 DPRINT("current->BaseAddress %x current->Length %x\n",
116 current->BaseAddress,current->Length);
117 if (current->BaseAddress >= Address &&
118 current->BaseAddress < (PVOID)((char*)Address+Length))
119 {
120 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
121 current);
122 return(current);
123 }
124 Extent = (ULONG)current->BaseAddress + current->Length;
125 if (Extent > (ULONG)Address &&
126 Extent < (ULONG)((char*)Address+Length))
127 {
128 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
129 current);
130 return(current);
131 }
132 if (current->BaseAddress <= Address &&
133 Extent >= (ULONG)((char*)Address+Length))
134 {
135 DPRINT("Finished MmOpenMemoryAreaByRegion() = %x\n",
136 current);
137 return(current);
138 }
139 if (current->BaseAddress >= (PVOID)((char*)Address+Length))
140 {
141 DPRINT("Finished MmOpenMemoryAreaByRegion()= NULL\n",0);
142 return(NULL);
143 }
144 current_entry = current_entry->Flink;
145 }
146 DPRINT("Finished MmOpenMemoryAreaByRegion() = NULL\n",0);
147 return(NULL);
148 }
149
150 static VOID MmInsertMemoryArea(PMADDRESS_SPACE AddressSpace,
151 MEMORY_AREA* marea)
152 {
153 PLIST_ENTRY ListHead;
154 PLIST_ENTRY current_entry;
155 PLIST_ENTRY inserted_entry = &marea->Entry;
156 MEMORY_AREA* current;
157 MEMORY_AREA* next;
158
159 DPRINT("MmInsertMemoryArea(marea %x)\n", marea);
160 DPRINT("marea->BaseAddress %x\n", marea->BaseAddress);
161 DPRINT("marea->Length %x\n", marea->Length);
162
163 ListHead = &AddressSpace->MAreaListHead;
164
165 current_entry = ListHead->Flink;
166 if (IsListEmpty(ListHead))
167 {
168 InsertHeadList(ListHead,&marea->Entry);
169 return;
170 }
171 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
172 if (current->BaseAddress > marea->BaseAddress)
173 {
174 InsertHeadList(ListHead,&marea->Entry);
175 return;
176 }
177 while (current_entry->Flink!=ListHead)
178 {
179 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
180 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
181 if (current->BaseAddress < marea->BaseAddress &&
182 current->Entry.Flink==ListHead)
183 {
184 current_entry->Flink = inserted_entry;
185 inserted_entry->Flink=ListHead;
186 inserted_entry->Blink=current_entry;
187 ListHead->Blink = inserted_entry;
188 return;
189 }
190 if (current->BaseAddress < marea->BaseAddress &&
191 next->BaseAddress > marea->BaseAddress)
192 {
193 inserted_entry->Flink = current_entry->Flink;
194 inserted_entry->Blink = current_entry;
195 inserted_entry->Flink->Blink = inserted_entry;
196 current_entry->Flink=inserted_entry;
197 return;
198 }
199 current_entry = current_entry->Flink;
200 }
201 InsertTailList(ListHead,inserted_entry);
202 }
203
204 static PVOID MmFindGapBottomUp(PMADDRESS_SPACE AddressSpace, ULONG Length, ULONG Granularity)
205 {
206 PLIST_ENTRY ListHead;
207 PLIST_ENTRY current_entry;
208 MEMORY_AREA* current;
209 MEMORY_AREA* next;
210 ULONG Gap;
211 PVOID Address;
212
213 DPRINT("MmFindGapBottomUp(Length %x)\n",Length);
214
215 #ifdef DBG
216 Length += PAGE_SIZE; /* For a guard page following the area */
217 #endif
218
219 ListHead = &AddressSpace->MAreaListHead;
220
221 current_entry = ListHead->Flink;
222 while (current_entry->Flink!=ListHead)
223 {
224 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
225 next = CONTAINING_RECORD(current_entry->Flink,MEMORY_AREA,Entry);
226 Address = (PVOID) ((char*)current->BaseAddress + PAGE_ROUND_UP(current->Length));
227 #ifdef DBG
228 Address = (PVOID) ((char *) Address + PAGE_SIZE); /* For a guard page preceding the area */
229 #endif
230 Address = (PVOID) MM_ROUND_UP(Address, Granularity);
231 if (Address < next->BaseAddress)
232 {
233 Gap = (char*)next->BaseAddress - ((char*)current->BaseAddress + PAGE_ROUND_UP(current->Length));
234 if (Gap >= Length)
235 {
236 return Address;
237 }
238 }
239 current_entry = current_entry->Flink;
240 }
241
242 if (current_entry == ListHead)
243 {
244 Address = (PVOID) MM_ROUND_UP(AddressSpace->LowestAddress, Granularity);
245 }
246 else
247 {
248 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
249 Address = (char*)current->BaseAddress + PAGE_ROUND_UP(current->Length);
250 #ifdef DBG
251 Address = (PVOID) ((char *) Address + PAGE_SIZE); /* For a guard page preceding the area */
252 #endif
253 Address = (PVOID) MM_ROUND_UP(Address, Granularity);
254 }
255 /* Check if enough space for the block */
256 if (AddressSpace->LowestAddress < KERNEL_BASE)
257 {
258 if ((ULONG_PTR) Address >= KERNEL_BASE || Length > KERNEL_BASE - (ULONG_PTR) Address)
259 {
260 DPRINT1("Failed to find gap\n");
261 return NULL;
262 }
263 }
264 else
265 {
266 if (Length >= ~ ((ULONG_PTR) 0) - (ULONG_PTR) Address)
267 {
268 DPRINT1("Failed to find gap\n");
269 return NULL;
270 }
271 }
272 return Address;
273 }
274
275
276 static PVOID MmFindGapTopDown(PMADDRESS_SPACE AddressSpace, ULONG Length, ULONG Granularity)
277 {
278 PLIST_ENTRY ListHead;
279 PLIST_ENTRY current_entry;
280 MEMORY_AREA* current;
281 ULONG Gap;
282 PVOID Address;
283 PVOID TopAddress;
284 PVOID BottomAddress;
285 PVOID HighestAddress;
286
287 DPRINT("MmFindGapTopDown(Length %lx)\n",Length);
288
289 #ifdef DBG
290 Length += PAGE_SIZE; /* For a guard page following the area */
291 #endif
292
293 if (AddressSpace->LowestAddress < KERNEL_BASE) //(ULONG_PTR)MmSystemRangeStart)
294 {
295 HighestAddress = MmHighestUserAddress;
296 }
297 else
298 {
299 HighestAddress = (PVOID)0xFFFFFFFF;
300 }
301
302 TopAddress = HighestAddress;
303
304 ListHead = &AddressSpace->MAreaListHead;
305 current_entry = ListHead->Blink;
306 while (current_entry->Blink != ListHead)
307 {
308 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
309 BottomAddress = (char*)current->BaseAddress + PAGE_ROUND_UP(current->Length);
310 #ifdef DBG
311 BottomAddress = (PVOID) ((char *) BottomAddress + PAGE_SIZE); /* For a guard page preceding the area */
312 #endif
313 BottomAddress = (PVOID) MM_ROUND_UP(BottomAddress, Granularity);
314 DPRINT("Base %p Length %lx\n", current->BaseAddress, PAGE_ROUND_UP(current->Length));
315
316 if (BottomAddress < TopAddress && BottomAddress < HighestAddress)
317 {
318 Gap = (char*)TopAddress - (char*) BottomAddress + 1;
319 DPRINT("Bottom %p Top %p Gap %lx\n", BottomAddress, TopAddress, Gap);
320 if (Gap >= Length)
321 {
322 DPRINT("Found gap at %p\n", (char*) TopAddress - Length);
323 return (PVOID) MM_ROUND_DOWN((char*) TopAddress - Length + 1, Granularity);
324 }
325 }
326 TopAddress = (char*)current->BaseAddress - 1;
327 current_entry = current_entry->Blink;
328 }
329
330 if (current_entry == ListHead)
331 {
332 Address = (PVOID) MM_ROUND_DOWN((char*) HighestAddress - Length + 1, Granularity);
333 }
334 else
335 {
336 Address = (PVOID) MM_ROUND_DOWN((char*)TopAddress - Length + 1, Granularity);
337 }
338
339 /* Check if enough space for the block */
340 if (AddressSpace->LowestAddress < KERNEL_BASE)
341 {
342 if ((ULONG_PTR) Address >= KERNEL_BASE || Length > KERNEL_BASE - (ULONG_PTR) Address)
343 {
344 DPRINT1("Failed to find gap\n");
345 return NULL;
346 }
347 }
348 else
349 {
350 if (Length >= ~ ((ULONG_PTR) 0) - (ULONG_PTR) Address)
351 {
352 DPRINT1("Failed to find gap\n");
353 return NULL;
354 }
355 }
356
357 DPRINT("Found gap at %p\n", Address);
358 return Address;
359 }
360
361
362 PVOID MmFindGap(PMADDRESS_SPACE AddressSpace, ULONG Length, ULONG Granularity, BOOL TopDown)
363 {
364 if (TopDown)
365 return MmFindGapTopDown(AddressSpace, Length, Granularity);
366
367 return MmFindGapBottomUp(AddressSpace, Length, Granularity);
368 }
369
370 ULONG MmFindGapAtAddress(PMADDRESS_SPACE AddressSpace, PVOID Address)
371 {
372 PLIST_ENTRY current_entry, ListHead;
373 PMEMORY_AREA current;
374
375 Address = (PVOID)PAGE_ROUND_DOWN(Address);
376
377 if (AddressSpace->LowestAddress < KERNEL_BASE)
378 {
379 if (Address >= (PVOID)KERNEL_BASE)
380 {
381 return 0;
382 }
383 }
384 else
385 {
386 if ((ULONG_PTR)Address < AddressSpace->LowestAddress)
387 {
388 return 0;
389 }
390 }
391
392 ListHead = &AddressSpace->MAreaListHead;
393
394 current_entry = ListHead->Flink;
395 while (current_entry != ListHead)
396 {
397 current = CONTAINING_RECORD(current_entry,MEMORY_AREA,Entry);
398 if (current->BaseAddress <= Address && (char*)Address < (char*)current->BaseAddress + current->Length)
399 {
400 return 0;
401 }
402 else if (current->BaseAddress > Address)
403 {
404 return (ULONG_PTR)current->BaseAddress - (ULONG_PTR)Address;
405 }
406 current_entry = current_entry->Flink;
407 }
408 if (AddressSpace->LowestAddress < KERNEL_BASE)
409 {
410 return KERNEL_BASE - (ULONG_PTR)Address;
411 }
412 else
413 {
414 return 0 - (ULONG_PTR)Address;
415 }
416 }
417
418 NTSTATUS INIT_FUNCTION
419 MmInitMemoryAreas(VOID)
420 /*
421 * FUNCTION: Initialize the memory area list
422 */
423 {
424 DPRINT("MmInitMemoryAreas()\n",0);
425 return(STATUS_SUCCESS);
426 }
427
428 NTSTATUS
429 MmFreeMemoryArea(PMADDRESS_SPACE AddressSpace,
430 PVOID BaseAddress,
431 ULONG Length,
432 VOID (*FreePage)(PVOID Context, MEMORY_AREA* MemoryArea,
433 PVOID Address, PFN_TYPE Page,
434 SWAPENTRY SwapEntry, BOOLEAN Dirty),
435 PVOID FreePageContext)
436 {
437 MEMORY_AREA* MemoryArea;
438 char* Address;
439 char* EndAddress;
440 PEPROCESS CurrentProcess = PsGetCurrentProcess();
441
442 DPRINT("MmFreeMemoryArea(AddressSpace %x, BaseAddress %x, Length %x,"
443 "FreePageContext %d)\n",AddressSpace,BaseAddress,Length,
444 FreePageContext);
445
446 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace,
447 BaseAddress);
448 if (MemoryArea == NULL)
449 {
450 KEBUGCHECK(0);
451 return(STATUS_UNSUCCESSFUL);
452 }
453 if (AddressSpace->Process != NULL &&
454 AddressSpace->Process != CurrentProcess)
455 {
456 KeAttachProcess(&AddressSpace->Process->Pcb);
457 }
458 EndAddress = (char*)MemoryArea->BaseAddress + PAGE_ROUND_UP(MemoryArea->Length);
459 for (Address = MemoryArea->BaseAddress; Address < EndAddress; Address += PAGE_SIZE)
460 {
461
462 if (MemoryArea->Type == MEMORY_AREA_IO_MAPPING)
463 {
464 MmRawDeleteVirtualMapping(Address);
465 }
466 else
467 {
468 BOOL Dirty = FALSE;
469 SWAPENTRY SwapEntry = 0;
470 PFN_TYPE Page = 0;
471
472
473 if (MmIsPageSwapEntry(AddressSpace->Process, Address))
474 {
475 MmDeletePageFileMapping(AddressSpace->Process, Address, &SwapEntry);
476 }
477 else
478 {
479 MmDeleteVirtualMapping(AddressSpace->Process, Address, FALSE, &Dirty, &Page);
480 }
481 if (FreePage != NULL)
482 {
483 FreePage(FreePageContext, MemoryArea, Address,
484 Page, SwapEntry, (BOOLEAN)Dirty);
485 }
486 }
487 }
488 if (AddressSpace->Process != NULL &&
489 AddressSpace->Process != CurrentProcess)
490 {
491 KeDetachProcess();
492 }
493 RemoveEntryList(&MemoryArea->Entry);
494 ExFreePool(MemoryArea);
495
496 DPRINT("MmFreeMemoryArea() succeeded\n");
497
498 return(STATUS_SUCCESS);
499 }
500
501 NTSTATUS MmCreateMemoryArea(PEPROCESS Process,
502 PMADDRESS_SPACE AddressSpace,
503 ULONG Type,
504 PVOID* BaseAddress,
505 ULONG Length,
506 ULONG Attributes,
507 MEMORY_AREA** Result,
508 BOOL FixedAddress,
509 BOOL TopDown,
510 PHYSICAL_ADDRESS BoundaryAddressMultiple)
511 /*
512 * FUNCTION: Create a memory area
513 * ARGUMENTS:
514 * AddressSpace = Address space to create the area in
515 * Type = Type of the address space
516 * BaseAddress =
517 * Length = Length to allocate
518 * Attributes = Protection attributes for the memory area
519 * Result = Receives a pointer to the memory area on exit
520 * RETURNS: Status
521 * NOTES: Lock the address space before calling this function
522 */
523 {
524 PVOID EndAddress;
525 ULONG Granularity;
526 ULONG tmpLength;
527 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %x,"
528 "*BaseAddress %x, Length %x, Attributes %x, Result %x)\n",
529 Type,BaseAddress,*BaseAddress,Length,Attributes,Result);
530
531 Granularity = (MEMORY_AREA_VIRTUAL_MEMORY == Type ? MM_VIRTMEM_GRANULARITY : PAGE_SIZE);
532 if ((*BaseAddress) == 0 && !FixedAddress)
533 {
534 tmpLength = PAGE_ROUND_UP(Length);
535 *BaseAddress = MmFindGap(AddressSpace,
536 PAGE_ROUND_UP(Length),
537 Granularity,
538 TopDown);
539 if ((*BaseAddress) == 0)
540 {
541 DPRINT("No suitable gap\n");
542 return STATUS_NO_MEMORY;
543 }
544 }
545 else
546 {
547 tmpLength = Length + ((ULONG_PTR) *BaseAddress
548 - (ULONG_PTR) MM_ROUND_DOWN(*BaseAddress, Granularity));
549 *BaseAddress = MM_ROUND_DOWN(*BaseAddress, Granularity);
550
551 if (AddressSpace->LowestAddress == KERNEL_BASE &&
552 (*BaseAddress) < (PVOID)KERNEL_BASE)
553 {
554 return STATUS_ACCESS_VIOLATION;
555 }
556
557 if (AddressSpace->LowestAddress < KERNEL_BASE &&
558 (PVOID)((char*)(*BaseAddress) + tmpLength) > (PVOID)KERNEL_BASE)
559 {
560 return STATUS_ACCESS_VIOLATION;
561 }
562
563 if (BoundaryAddressMultiple.QuadPart != 0)
564 {
565 EndAddress = ((char*)(*BaseAddress)) + tmpLength-1;
566 ASSERT(((DWORD_PTR)*BaseAddress/BoundaryAddressMultiple.QuadPart) == ((DWORD_PTR)EndAddress/BoundaryAddressMultiple.QuadPart));
567 }
568
569 if (MmOpenMemoryAreaByRegion(AddressSpace,
570 *BaseAddress,
571 tmpLength)!=NULL)
572 {
573 DPRINT("Memory area already occupied\n");
574 return STATUS_CONFLICTING_ADDRESSES;
575 }
576 }
577
578 *Result = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
579 TAG_MAREA);
580 RtlZeroMemory(*Result,sizeof(MEMORY_AREA));
581 (*Result)->Type = Type;
582 (*Result)->BaseAddress = *BaseAddress;
583 (*Result)->Length = tmpLength;
584 (*Result)->Attributes = Attributes;
585 (*Result)->LockCount = 0;
586 (*Result)->Process = Process;
587 (*Result)->PageOpCount = 0;
588 (*Result)->DeleteInProgress = FALSE;
589
590 MmInsertMemoryArea(AddressSpace, *Result);
591
592 DPRINT("MmCreateMemoryArea() succeeded\n");
593 return STATUS_SUCCESS;
594 }
595
596
597 void
598 MmReleaseMemoryAreaIfDecommitted(PEPROCESS Process,
599 PMADDRESS_SPACE AddressSpace,
600 PVOID BaseAddress)
601 {
602 PMEMORY_AREA MemoryArea;
603 PLIST_ENTRY Entry;
604 PMM_REGION Region;
605 BOOLEAN Reserved;
606
607 MemoryArea = MmOpenMemoryAreaByAddress(AddressSpace, BaseAddress);
608 if (NULL != MemoryArea)
609 {
610 Entry = MemoryArea->Data.VirtualMemoryData.RegionListHead.Flink;
611 Reserved = TRUE;
612 while (Reserved && Entry != &MemoryArea->Data.VirtualMemoryData.RegionListHead)
613 {
614 Region = CONTAINING_RECORD(Entry, MM_REGION, RegionListEntry);
615 Reserved = (MEM_RESERVE == Region->Type);
616 Entry = Entry->Flink;
617 }
618
619 if (Reserved)
620 {
621 MmFreeVirtualMemory(Process, MemoryArea);
622 }
623 }
624 }
625
626 /* EOF */