2 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * PROJECT: ReactOS kernel
20 * FILE: ntoskrnl/mm/marea.c
21 * PURPOSE: Implements memory areas
23 * PROGRAMMERS: Rex Jolliff
33 * Thomas Weidenmueller
34 * Gunnar Andre' Dalsnes
42 /* INCLUDES *****************************************************************/
48 MEMORY_AREA MiStaticMemoryAreas
[MI_STATIC_MEMORY_AREAS
];
49 ULONG MiStaticMemoryAreaCount
;
51 /* FUNCTIONS *****************************************************************/
54 * @name MmIterateFirstNode
57 * Head node of the MEMORY_AREA tree.
59 * @return The leftmost MEMORY_AREA node (ie. the one with lowest
63 static PMEMORY_AREA
MmIterateFirstNode(PMEMORY_AREA Node
)
65 while (Node
->LeftChild
!= NULL
)
66 Node
= Node
->LeftChild
;
72 * @name MmIterateNextNode
75 * Current node in the tree.
77 * @return Next node in the tree (sorted by address).
80 static PMEMORY_AREA
MmIterateNextNode(PMEMORY_AREA Node
)
82 if (Node
->RightChild
!= NULL
)
84 Node
= Node
->RightChild
;
85 while (Node
->LeftChild
!= NULL
)
86 Node
= Node
->LeftChild
;
90 PMEMORY_AREA TempNode
= NULL
;
94 /* Check if we're at the end of tree. */
95 if (Node
->Parent
== NULL
)
101 while (TempNode
== Node
->RightChild
);
107 * @name MmIterateLastNode
110 * Head node of the MEMORY_AREA tree.
112 * @return The rightmost MEMORY_AREA node (ie. the one with highest
116 static PMEMORY_AREA
MmIterateLastNode(PMEMORY_AREA Node
)
118 while (Node
->RightChild
!= NULL
)
119 Node
= Node
->RightChild
;
125 * @name MmIteratePreviousNode
128 * Current node in the tree.
130 * @return Previous node in the tree (sorted by address).
133 static PMEMORY_AREA
MmIteratePrevNode(PMEMORY_AREA Node
)
135 if (Node
->LeftChild
!= NULL
)
137 Node
= Node
->LeftChild
;
138 while (Node
->RightChild
!= NULL
)
139 Node
= Node
->RightChild
;
143 PMEMORY_AREA TempNode
= NULL
;
147 /* Check if we're at the end of tree. */
148 if (Node
->Parent
== NULL
)
154 while (TempNode
== Node
->LeftChild
);
160 MmLocateMemoryAreaByAddress(
161 PMMSUPPORT AddressSpace
,
164 PMEMORY_AREA Node
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
166 DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
167 AddressSpace
, Address
);
171 if (Address
< Node
->StartingAddress
)
172 Node
= Node
->LeftChild
;
173 else if (Address
>= Node
->EndingAddress
)
174 Node
= Node
->RightChild
;
177 DPRINT("MmLocateMemoryAreaByAddress(%p): %p [%p - %p]\n",
178 Address
, Node
, Node
->StartingAddress
, Node
->EndingAddress
);
183 DPRINT("MmLocateMemoryAreaByAddress(%p): 0\n", Address
);
188 MmLocateMemoryAreaByRegion(
189 PMMSUPPORT AddressSpace
,
194 PVOID Extent
= (PVOID
)((ULONG_PTR
)Address
+ Length
);
196 /* Special case for empty tree. */
197 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
200 /* Traverse the tree from left to right. */
201 for (Node
= MmIterateFirstNode((PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
);
203 Node
= MmIterateNextNode(Node
))
205 if (Node
->StartingAddress
>= Address
&&
206 Node
->StartingAddress
< Extent
)
208 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
209 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
210 Node
->EndingAddress
);
213 if (Node
->EndingAddress
> Address
&&
214 Node
->EndingAddress
< Extent
)
216 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
217 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
218 Node
->EndingAddress
);
221 if (Node
->StartingAddress
<= Address
&&
222 Node
->EndingAddress
>= Extent
)
224 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
225 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
226 Node
->EndingAddress
);
229 if (Node
->StartingAddress
>= Extent
)
231 DPRINT("Finished MmLocateMemoryAreaByRegion() = NULL\n");
240 * @name MmCompressHelper
242 * This is helper of MmRebalanceTree. Performs a compression transformation
243 * count times, starting at root.
248 PMMSUPPORT AddressSpace
,
251 PMEMORY_AREA Root
= NULL
;
252 PMEMORY_AREA Red
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
253 PMEMORY_AREA Black
= Red
->LeftChild
;
258 Root
->LeftChild
= Black
;
260 AddressSpace
->WorkingSetExpansionLinks
.Flink
= (PVOID
)Black
;
261 Black
->Parent
= Root
;
262 Red
->LeftChild
= Black
->RightChild
;
263 if (Black
->RightChild
)
264 Black
->RightChild
->Parent
= Red
;
265 Black
->RightChild
= Red
;
271 Red
= Root
->LeftChild
;
272 Black
= Red
->LeftChild
;
278 * @name MmRebalanceTree
280 * Rebalance a memory area tree using the Tree->Vine->Balanced Tree
281 * method described in libavl documentation in chapter 4.12.
282 * (http://www.stanford.edu/~blp/avl/libavl.html/)
287 PMMSUPPORT AddressSpace
)
289 PMEMORY_AREA PreviousNode
;
290 PMEMORY_AREA CurrentNode
;
291 PMEMORY_AREA TempNode
;
293 ULONG Vine
; /* Number of nodes in main vine. */
294 ULONG Leaves
; /* Nodes in incomplete bottom level, if any. */
295 INT Height
; /* Height of produced balanced tree. */
297 /* Transform the tree into Vine. */
300 CurrentNode
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
301 while (CurrentNode
!= NULL
)
303 if (CurrentNode
->RightChild
== NULL
)
305 PreviousNode
= CurrentNode
;
306 CurrentNode
= CurrentNode
->LeftChild
;
311 TempNode
= CurrentNode
->RightChild
;
313 CurrentNode
->RightChild
= TempNode
->LeftChild
;
314 if (TempNode
->LeftChild
)
315 TempNode
->LeftChild
->Parent
= CurrentNode
;
317 TempNode
->LeftChild
= CurrentNode
;
318 CurrentNode
->Parent
= TempNode
;
320 CurrentNode
= TempNode
;
322 if (PreviousNode
!= NULL
)
323 PreviousNode
->LeftChild
= TempNode
;
325 AddressSpace
->WorkingSetExpansionLinks
.Flink
= (PVOID
)TempNode
;
326 TempNode
->Parent
= PreviousNode
;
330 /* Transform Vine back into a balanced tree. */
332 Leaves
= NodeCount
+ 1;
335 ULONG Next
= Leaves
& (Leaves
- 1);
340 Leaves
= NodeCount
+ 1 - Leaves
;
342 MmCompressHelper(AddressSpace
, Leaves
);
344 Vine
= NodeCount
- Leaves
;
345 Height
= 1 + (Leaves
> 0);
348 MmCompressHelper(AddressSpace
, Vine
/ 2);
356 MiInsertVad(IN PMMVAD Vad
,
357 IN PEPROCESS Process
);
361 MiMakeProtectionMask(
367 PMMSUPPORT AddressSpace
,
371 PMEMORY_AREA PreviousNode
;
374 /* Build a lame VAD if this is a user-space allocation */
375 if ((marea
->EndingAddress
< MmSystemRangeStart
) && (marea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
))
379 ASSERT(marea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
|| marea
->Type
== MEMORY_AREA_SECTION_VIEW
);
380 Vad
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MMVAD
), 'Fake');
382 RtlZeroMemory(Vad
, sizeof(MMVAD
));
383 Vad
->StartingVpn
= PAGE_ROUND_DOWN(marea
->StartingAddress
) >> PAGE_SHIFT
;
385 * For some strange reason, it is perfectly valid to create a MAREA from 0x1000 to... 0x1000.
386 * In a normal OS/Memory Manager, this would be retarded, but ReactOS allows this (how it works
387 * I don't even want to know).
389 if (marea
->EndingAddress
!= marea
->StartingAddress
)
391 Vad
->EndingVpn
= PAGE_ROUND_DOWN((ULONG_PTR
)marea
->EndingAddress
- 1) >> PAGE_SHIFT
;
395 Vad
->EndingVpn
= Vad
->StartingVpn
;
397 Vad
->u
.VadFlags
.Spare
= 1;
398 Vad
->u
.VadFlags
.PrivateMemory
= 1;
399 Vad
->u
.VadFlags
.Protection
= MiMakeProtectionMask(marea
->Protect
);
400 MiInsertVad(Vad
, MmGetAddressSpaceOwner(AddressSpace
));
408 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
410 AddressSpace
->WorkingSetExpansionLinks
.Flink
= (PVOID
)marea
;
411 marea
->LeftChild
= marea
->RightChild
= marea
->Parent
= NULL
;
415 Node
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
418 DPRINT("marea->EndingAddress: %p Node->StartingAddress: %p\n",
419 marea
->EndingAddress
, Node
->StartingAddress
);
420 DPRINT("marea->StartingAddress: %p Node->EndingAddress: %p\n",
421 marea
->StartingAddress
, Node
->EndingAddress
);
422 ASSERT(marea
->EndingAddress
<= Node
->StartingAddress
||
423 marea
->StartingAddress
>= Node
->EndingAddress
);
424 ASSERT(marea
->StartingAddress
!= Node
->StartingAddress
);
428 if (marea
->StartingAddress
< Node
->StartingAddress
)
429 Node
= Node
->LeftChild
;
431 Node
= Node
->RightChild
;
438 MmRebalanceTree(AddressSpace
);
439 PreviousNode
= Node
->Parent
;
443 while (Node
!= NULL
);
445 marea
->LeftChild
= marea
->RightChild
= NULL
;
446 marea
->Parent
= PreviousNode
;
447 if (marea
->StartingAddress
< PreviousNode
->StartingAddress
)
448 PreviousNode
->LeftChild
= marea
;
450 PreviousNode
->RightChild
= marea
;
455 PMMSUPPORT AddressSpace
,
457 ULONG_PTR Granularity
)
459 PVOID LowestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ? MM_LOWEST_USER_ADDRESS
: MmSystemRangeStart
;
460 PVOID HighestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ?
461 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
462 PVOID AlignedAddress
;
464 PMEMORY_AREA FirstNode
;
465 PMEMORY_AREA PreviousNode
;
467 DPRINT("LowestAddress: %p HighestAddress: %p\n",
468 LowestAddress
, HighestAddress
);
470 AlignedAddress
= MM_ROUND_UP(LowestAddress
, Granularity
);
472 /* Special case for empty tree. */
473 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
475 if ((ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
477 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
478 return AlignedAddress
;
480 DPRINT("MmFindGapBottomUp: 0\n");
484 /* Go to the node with lowest address in the tree. */
485 FirstNode
= Node
= MmIterateFirstNode((PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
);
487 /* Traverse the tree from left to right. */
491 Node
= MmIterateNextNode(Node
);
495 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
496 if (AlignedAddress
>= LowestAddress
)
498 if (Node
->StartingAddress
> AlignedAddress
&&
499 (ULONG_PTR
)Node
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
501 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
502 ASSERT(AlignedAddress
>= LowestAddress
);
503 return AlignedAddress
;
509 /* Check if there is enough space after the last memory area. */
510 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
511 if ((ULONG_PTR
)HighestAddress
> (ULONG_PTR
)AlignedAddress
&&
512 (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
514 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
515 ASSERT(AlignedAddress
>= LowestAddress
);
516 return AlignedAddress
;
519 /* Check if there is enough space before the first memory area. */
520 AlignedAddress
= MM_ROUND_UP(LowestAddress
, Granularity
);
521 if (FirstNode
->StartingAddress
> AlignedAddress
&&
522 (ULONG_PTR
)FirstNode
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
524 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
525 ASSERT(AlignedAddress
>= LowestAddress
);
526 return AlignedAddress
;
529 DPRINT("MmFindGapBottomUp: 0\n");
536 PMMSUPPORT AddressSpace
,
538 ULONG_PTR Granularity
)
540 PVOID LowestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ? MM_LOWEST_USER_ADDRESS
: MmSystemRangeStart
;
541 PVOID HighestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ?
542 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
543 PVOID AlignedAddress
;
545 PMEMORY_AREA PreviousNode
;
547 DPRINT("LowestAddress: %p HighestAddress: %p\n",
548 LowestAddress
, HighestAddress
);
550 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)HighestAddress
- Length
+ 1, Granularity
);
552 /* Check for overflow. */
553 if (AlignedAddress
> HighestAddress
)
556 /* Special case for empty tree. */
557 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
559 if (AlignedAddress
>= LowestAddress
)
561 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
562 return AlignedAddress
;
564 DPRINT("MmFindGapTopDown: 0\n");
568 /* Go to the node with highest address in the tree. */
569 Node
= MmIterateLastNode((PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
);
571 /* Check if there is enough space after the last memory area. */
572 if (Node
->EndingAddress
<= AlignedAddress
)
574 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
575 return AlignedAddress
;
578 /* Traverse the tree from left to right. */
582 Node
= MmIteratePrevNode(Node
);
586 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
588 /* Check for overflow. */
589 if (AlignedAddress
> PreviousNode
->StartingAddress
)
592 if (Node
->EndingAddress
<= AlignedAddress
)
594 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
595 return AlignedAddress
;
601 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
603 /* Check for overflow. */
604 if (AlignedAddress
> PreviousNode
->StartingAddress
)
607 if (AlignedAddress
>= LowestAddress
)
609 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
610 return AlignedAddress
;
613 DPRINT("MmFindGapTopDown: 0\n");
620 PMMSUPPORT AddressSpace
,
622 ULONG_PTR Granularity
,
626 return MmFindGapTopDown(AddressSpace
, Length
, Granularity
);
628 return MmFindGapBottomUp(AddressSpace
, Length
, Granularity
);
633 PMMSUPPORT AddressSpace
,
636 PMEMORY_AREA Node
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
637 PMEMORY_AREA RightNeighbour
= NULL
;
638 PVOID LowestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ? MM_LOWEST_USER_ADDRESS
: MmSystemRangeStart
;
639 PVOID HighestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ?
640 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
642 Address
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
644 if (LowestAddress
< MmSystemRangeStart
)
646 if (Address
>= MmSystemRangeStart
)
653 if (Address
< LowestAddress
)
661 if (Address
< Node
->StartingAddress
)
663 RightNeighbour
= Node
;
664 Node
= Node
->LeftChild
;
666 else if (Address
>= Node
->EndingAddress
)
668 Node
= Node
->RightChild
;
672 DPRINT("MmFindGapAtAddress: 0\n");
679 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
680 (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
);
681 return (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
;
685 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
686 (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
);
687 return (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
;
693 MiRemoveNode(IN PMMADDRESS_NODE Node
,
694 IN PMM_AVL_TABLE Table
);
697 * @name MmFreeMemoryArea
699 * Free an existing memory area.
701 * @param AddressSpace
702 * Address space to free the area from.
704 * Memory area we're about to free.
706 * Callback function for each freed page.
707 * @param FreePageContext
708 * Context passed to the callback function.
712 * @remarks Lock the address space before calling this function.
717 PMMSUPPORT AddressSpace
,
718 PMEMORY_AREA MemoryArea
,
719 PMM_FREE_PAGE_FUNC FreePage
,
720 PVOID FreePageContext
)
722 PMEMORY_AREA
*ParentReplace
;
726 if (MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
)
728 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
729 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
731 if (Process
!= NULL
&&
732 Process
!= CurrentProcess
)
734 KeAttachProcess(&Process
->Pcb
);
737 EndAddress
= MM_ROUND_UP(MemoryArea
->EndingAddress
, PAGE_SIZE
);
738 for (Address
= (ULONG_PTR
)MemoryArea
->StartingAddress
;
739 Address
< (ULONG_PTR
)EndAddress
;
740 Address
+= PAGE_SIZE
)
742 BOOLEAN Dirty
= FALSE
;
743 SWAPENTRY SwapEntry
= 0;
746 if (MmIsPageSwapEntry(Process
, (PVOID
)Address
))
748 MmDeletePageFileMapping(Process
, (PVOID
)Address
, &SwapEntry
);
752 MmDeleteVirtualMapping(Process
, (PVOID
)Address
, FALSE
, &Dirty
, &Page
);
754 if (FreePage
!= NULL
)
756 FreePage(FreePageContext
, MemoryArea
, (PVOID
)Address
,
757 Page
, SwapEntry
, (BOOLEAN
)Dirty
);
761 if (Process
!= NULL
&&
762 Process
!= CurrentProcess
)
769 ASSERT(MemoryArea
->EndingAddress
< MmSystemRangeStart
);
770 ASSERT(MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
|| MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
);
772 /* MmCleanProcessAddressSpace might have removed it (and this would be MmDeleteProcessAdressSpace) */
773 ASSERT(((PMMVAD
)MemoryArea
->Vad
)->u
.VadFlags
.Spare
!= 0);
774 if (((PMMVAD
)MemoryArea
->Vad
)->u
.VadFlags
.Spare
== 1)
776 MiRemoveNode(MemoryArea
->Vad
, &Process
->VadRoot
);
779 ExFreePool(MemoryArea
->Vad
);
780 MemoryArea
->Vad
= NULL
;
784 /* Remove the tree item. */
786 if (MemoryArea
->Parent
!= NULL
)
788 if (MemoryArea
->Parent
->LeftChild
== MemoryArea
)
789 ParentReplace
= &MemoryArea
->Parent
->LeftChild
;
791 ParentReplace
= &MemoryArea
->Parent
->RightChild
;
794 ParentReplace
= (PMEMORY_AREA
*)&AddressSpace
->WorkingSetExpansionLinks
.Flink
;
796 if (MemoryArea
->RightChild
== NULL
)
798 *ParentReplace
= MemoryArea
->LeftChild
;
799 if (MemoryArea
->LeftChild
)
800 MemoryArea
->LeftChild
->Parent
= MemoryArea
->Parent
;
804 if (MemoryArea
->RightChild
->LeftChild
== NULL
)
806 MemoryArea
->RightChild
->LeftChild
= MemoryArea
->LeftChild
;
807 if (MemoryArea
->LeftChild
)
808 MemoryArea
->LeftChild
->Parent
= MemoryArea
->RightChild
;
810 *ParentReplace
= MemoryArea
->RightChild
;
811 MemoryArea
->RightChild
->Parent
= MemoryArea
->Parent
;
815 PMEMORY_AREA LowestNode
;
817 LowestNode
= MemoryArea
->RightChild
->LeftChild
;
818 while (LowestNode
->LeftChild
!= NULL
)
819 LowestNode
= LowestNode
->LeftChild
;
821 LowestNode
->Parent
->LeftChild
= LowestNode
->RightChild
;
822 if (LowestNode
->RightChild
)
823 LowestNode
->RightChild
->Parent
= LowestNode
->Parent
;
825 LowestNode
->LeftChild
= MemoryArea
->LeftChild
;
826 if (MemoryArea
->LeftChild
)
827 MemoryArea
->LeftChild
->Parent
= LowestNode
;
829 LowestNode
->RightChild
= MemoryArea
->RightChild
;
830 MemoryArea
->RightChild
->Parent
= LowestNode
;
832 *ParentReplace
= LowestNode
;
833 LowestNode
->Parent
= MemoryArea
->Parent
;
838 ExFreePoolWithTag(MemoryArea
, TAG_MAREA
);
840 DPRINT("MmFreeMemoryAreaByNode() succeeded\n");
842 return STATUS_SUCCESS
;
846 * @name MmCreateMemoryArea
848 * Create a memory area.
850 * @param AddressSpace
851 * Address space to create the area in.
853 * Type of the memory area.
855 * Base address for the memory area we're about the create. On
856 * input it contains either 0 (auto-assign address) or preferred
857 * address. On output it contains the starting address of the
858 * newly created area.
860 * Length of the area to allocate.
862 * Protection attributes for the memory area.
864 * Receives a pointer to the memory area on successful exit.
868 * @remarks Lock the address space before calling this function.
872 MmCreateMemoryArea(PMMSUPPORT AddressSpace
,
877 PMEMORY_AREA
*Result
,
878 BOOLEAN FixedAddress
,
879 ULONG AllocationFlags
,
880 PHYSICAL_ADDRESS BoundaryAddressMultiple
)
885 PMEMORY_AREA MemoryArea
;
887 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
888 "*BaseAddress %p, Length %p, AllocationFlags %x, "
889 "FixedAddress %x, Result %p)\n",
890 Type
, BaseAddress
, *BaseAddress
, Length
, AllocationFlags
,
891 FixedAddress
, Result
);
893 Granularity
= (MEMORY_AREA_VIRTUAL_MEMORY
== Type
? MM_VIRTMEM_GRANULARITY
: PAGE_SIZE
);
894 if ((*BaseAddress
) == 0 && !FixedAddress
)
896 tmpLength
= PAGE_ROUND_UP(Length
);
897 *BaseAddress
= MmFindGap(AddressSpace
,
900 (AllocationFlags
& MEM_TOP_DOWN
) == MEM_TOP_DOWN
);
901 if ((*BaseAddress
) == 0)
903 DPRINT("No suitable gap\n");
904 return STATUS_NO_MEMORY
;
909 tmpLength
= Length
+ ((ULONG_PTR
) *BaseAddress
910 - (ULONG_PTR
) MM_ROUND_DOWN(*BaseAddress
, Granularity
));
911 *BaseAddress
= MM_ROUND_DOWN(*BaseAddress
, Granularity
);
913 if (!MmGetAddressSpaceOwner(AddressSpace
) && *BaseAddress
< MmSystemRangeStart
)
915 return STATUS_ACCESS_VIOLATION
;
918 if (MmGetAddressSpaceOwner(AddressSpace
) &&
919 (ULONG_PTR
)(*BaseAddress
) + tmpLength
> (ULONG_PTR
)MmSystemRangeStart
)
921 return STATUS_ACCESS_VIOLATION
;
924 if (BoundaryAddressMultiple
.QuadPart
!= 0)
926 EndAddress
= ((char*)(*BaseAddress
)) + tmpLength
-1;
927 ASSERT(((ULONG_PTR
)*BaseAddress
/BoundaryAddressMultiple
.QuadPart
) == ((DWORD_PTR
)EndAddress
/BoundaryAddressMultiple
.QuadPart
));
930 if (MmLocateMemoryAreaByRegion(AddressSpace
,
934 DPRINT("Memory area already occupied\n");
935 return STATUS_CONFLICTING_ADDRESSES
;
940 // Is this a static memory area?
942 if (Type
& MEMORY_AREA_STATIC
)
945 // Use the static array instead of the pool
947 ASSERT(MiStaticMemoryAreaCount
< MI_STATIC_MEMORY_AREAS
);
948 MemoryArea
= &MiStaticMemoryAreas
[MiStaticMemoryAreaCount
++];
949 Type
&= ~MEMORY_AREA_STATIC
;
954 // Allocate the memory area from nonpaged pool
956 MemoryArea
= ExAllocatePoolWithTag(NonPagedPool
,
961 if (!MemoryArea
) return STATUS_NO_MEMORY
;
963 RtlZeroMemory(MemoryArea
, sizeof(MEMORY_AREA
));
964 MemoryArea
->Type
= Type
;
965 MemoryArea
->StartingAddress
= *BaseAddress
;
966 MemoryArea
->EndingAddress
= (PVOID
)((ULONG_PTR
)*BaseAddress
+ tmpLength
);
967 MemoryArea
->Protect
= Protect
;
968 MemoryArea
->Flags
= AllocationFlags
;
969 //MemoryArea->LockCount = 0;
970 MemoryArea
->PageOpCount
= 0;
971 MemoryArea
->DeleteInProgress
= FALSE
;
973 MmInsertMemoryArea(AddressSpace
, MemoryArea
);
975 *Result
= MemoryArea
;
977 DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress
);
978 return STATUS_SUCCESS
;
982 MmMapMemoryArea(PVOID BaseAddress
,
990 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
994 Status
= MmRequestPageMemoryConsumer(Consumer
, TRUE
, &Page
);
995 if (!NT_SUCCESS(Status
))
997 DPRINT1("Unable to allocate page\n");
998 KeBugCheck(MEMORY_MANAGEMENT
);
1000 Status
= MmCreateVirtualMapping (NULL
,
1001 (PVOID
)((ULONG_PTR
)BaseAddress
+ (i
* PAGE_SIZE
)),
1005 if (!NT_SUCCESS(Status
))
1007 DPRINT1("Unable to create virtual mapping\n");
1008 KeBugCheck(MEMORY_MANAGEMENT
);
1015 MmDeleteProcessAddressSpace(PEPROCESS Process
)
1018 PMEMORY_AREA MemoryArea
;
1020 DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process
,
1021 Process
->ImageFileName
);
1023 RemoveEntryList(&Process
->MmProcessLinks
);
1025 MmLockAddressSpace(&Process
->Vm
);
1027 while ((MemoryArea
= (PMEMORY_AREA
)Process
->Vm
.WorkingSetExpansionLinks
.Flink
) != NULL
)
1029 switch (MemoryArea
->Type
)
1031 case MEMORY_AREA_SECTION_VIEW
:
1032 Address
= (PVOID
)MemoryArea
->StartingAddress
;
1033 MmUnlockAddressSpace(&Process
->Vm
);
1034 MmUnmapViewOfSection(Process
, Address
);
1035 MmLockAddressSpace(&Process
->Vm
);
1038 case MEMORY_AREA_VIRTUAL_MEMORY
:
1039 MmFreeVirtualMemory(Process
, MemoryArea
);
1042 case MEMORY_AREA_OWNED_BY_ARM3
:
1043 MmFreeMemoryArea(&Process
->Vm
,
1050 KeBugCheck(MEMORY_MANAGEMENT
);
1054 MmUnlockAddressSpace(&Process
->Vm
);
1056 DPRINT("Finished MmReleaseMmInfo()\n");
1057 return(STATUS_SUCCESS
);