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 #include "ARM3/miarm.h"
50 MEMORY_AREA MiStaticMemoryAreas
[MI_STATIC_MEMORY_AREAS
];
51 ULONG MiStaticMemoryAreaCount
;
53 /* FUNCTIONS *****************************************************************/
56 * @name MmIterateFirstNode
59 * Head node of the MEMORY_AREA tree.
61 * @return The leftmost MEMORY_AREA node (ie. the one with lowest
65 static PMEMORY_AREA
MmIterateFirstNode(PMEMORY_AREA Node
)
67 while (Node
->LeftChild
!= NULL
)
68 Node
= Node
->LeftChild
;
74 * @name MmIterateNextNode
77 * Current node in the tree.
79 * @return Next node in the tree (sorted by address).
82 static PMEMORY_AREA
MmIterateNextNode(PMEMORY_AREA Node
)
84 if (Node
->RightChild
!= NULL
)
86 Node
= Node
->RightChild
;
87 while (Node
->LeftChild
!= NULL
)
88 Node
= Node
->LeftChild
;
92 PMEMORY_AREA TempNode
= NULL
;
96 /* Check if we're at the end of tree. */
97 if (Node
->Parent
== NULL
)
103 while (TempNode
== Node
->RightChild
);
109 * @name MmIterateLastNode
112 * Head node of the MEMORY_AREA tree.
114 * @return The rightmost MEMORY_AREA node (ie. the one with highest
118 static PMEMORY_AREA
MmIterateLastNode(PMEMORY_AREA Node
)
120 while (Node
->RightChild
!= NULL
)
121 Node
= Node
->RightChild
;
127 * @name MmIteratePreviousNode
130 * Current node in the tree.
132 * @return Previous node in the tree (sorted by address).
135 static PMEMORY_AREA
MmIteratePrevNode(PMEMORY_AREA Node
)
137 if (Node
->LeftChild
!= NULL
)
139 Node
= Node
->LeftChild
;
140 while (Node
->RightChild
!= NULL
)
141 Node
= Node
->RightChild
;
145 PMEMORY_AREA TempNode
= NULL
;
149 /* Check if we're at the end of tree. */
150 if (Node
->Parent
== NULL
)
156 while (TempNode
== Node
->LeftChild
);
162 MmLocateMemoryAreaByAddress(
163 PMMSUPPORT AddressSpace
,
166 PMEMORY_AREA Node
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
168 DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
169 AddressSpace
, Address
);
173 if (Address
< Node
->StartingAddress
)
174 Node
= Node
->LeftChild
;
175 else if (Address
>= Node
->EndingAddress
)
176 Node
= Node
->RightChild
;
179 DPRINT("MmLocateMemoryAreaByAddress(%p): %p [%p - %p]\n",
180 Address
, Node
, Node
->StartingAddress
, Node
->EndingAddress
);
185 DPRINT("MmLocateMemoryAreaByAddress(%p): 0\n", Address
);
190 MmLocateMemoryAreaByRegion(
191 PMMSUPPORT AddressSpace
,
196 PVOID Extent
= (PVOID
)((ULONG_PTR
)Address
+ Length
);
198 /* Special case for empty tree. */
199 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
202 /* Traverse the tree from left to right. */
203 for (Node
= MmIterateFirstNode((PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
);
205 Node
= MmIterateNextNode(Node
))
207 if (Node
->StartingAddress
>= Address
&&
208 Node
->StartingAddress
< Extent
)
210 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
211 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
212 Node
->EndingAddress
);
215 if (Node
->EndingAddress
> Address
&&
216 Node
->EndingAddress
< Extent
)
218 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
219 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
220 Node
->EndingAddress
);
223 if (Node
->StartingAddress
<= Address
&&
224 Node
->EndingAddress
>= Extent
)
226 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
227 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
228 Node
->EndingAddress
);
231 if (Node
->StartingAddress
>= Extent
)
233 DPRINT("Finished MmLocateMemoryAreaByRegion() = NULL\n");
242 * @name MmCompressHelper
244 * This is helper of MmRebalanceTree. Performs a compression transformation
245 * count times, starting at root.
250 PMMSUPPORT AddressSpace
,
253 PMEMORY_AREA Root
= NULL
;
254 PMEMORY_AREA Red
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
255 PMEMORY_AREA Black
= Red
->LeftChild
;
260 Root
->LeftChild
= Black
;
262 AddressSpace
->WorkingSetExpansionLinks
.Flink
= (PVOID
)Black
;
263 Black
->Parent
= Root
;
264 Red
->LeftChild
= Black
->RightChild
;
265 if (Black
->RightChild
)
266 Black
->RightChild
->Parent
= Red
;
267 Black
->RightChild
= Red
;
273 Red
= Root
->LeftChild
;
274 Black
= Red
->LeftChild
;
280 * @name MmRebalanceTree
282 * Rebalance a memory area tree using the Tree->Vine->Balanced Tree
283 * method described in libavl documentation in chapter 4.12.
284 * (http://www.stanford.edu/~blp/avl/libavl.html/)
289 PMMSUPPORT AddressSpace
)
291 PMEMORY_AREA PreviousNode
;
292 PMEMORY_AREA CurrentNode
;
293 PMEMORY_AREA TempNode
;
295 ULONG Vine
; /* Number of nodes in main vine. */
296 ULONG Leaves
; /* Nodes in incomplete bottom level, if any. */
297 INT Height
; /* Height of produced balanced tree. */
299 /* Transform the tree into Vine. */
302 CurrentNode
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
303 while (CurrentNode
!= NULL
)
305 if (CurrentNode
->RightChild
== NULL
)
307 PreviousNode
= CurrentNode
;
308 CurrentNode
= CurrentNode
->LeftChild
;
313 TempNode
= CurrentNode
->RightChild
;
315 CurrentNode
->RightChild
= TempNode
->LeftChild
;
316 if (TempNode
->LeftChild
)
317 TempNode
->LeftChild
->Parent
= CurrentNode
;
319 TempNode
->LeftChild
= CurrentNode
;
320 CurrentNode
->Parent
= TempNode
;
322 CurrentNode
= TempNode
;
324 if (PreviousNode
!= NULL
)
325 PreviousNode
->LeftChild
= TempNode
;
327 AddressSpace
->WorkingSetExpansionLinks
.Flink
= (PVOID
)TempNode
;
328 TempNode
->Parent
= PreviousNode
;
332 /* Transform Vine back into a balanced tree. */
334 Leaves
= NodeCount
+ 1;
337 ULONG Next
= Leaves
& (Leaves
- 1);
342 Leaves
= NodeCount
+ 1 - Leaves
;
344 MmCompressHelper(AddressSpace
, Leaves
);
346 Vine
= NodeCount
- Leaves
;
347 Height
= 1 + (Leaves
> 0);
350 MmCompressHelper(AddressSpace
, Vine
/ 2);
358 MiInsertVad(IN PMMVAD Vad
,
359 IN PEPROCESS Process
);
363 MiMakeProtectionMask(
369 PMMSUPPORT AddressSpace
,
373 PMEMORY_AREA PreviousNode
;
376 /* Build a lame VAD if this is a user-space allocation */
377 if ((marea
->EndingAddress
< MmSystemRangeStart
) && (marea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
))
381 ASSERT(marea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
|| marea
->Type
== MEMORY_AREA_SECTION_VIEW
);
382 Vad
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MMVAD
), TAG_MVAD
);
384 RtlZeroMemory(Vad
, sizeof(MMVAD
));
385 Vad
->StartingVpn
= PAGE_ROUND_DOWN(marea
->StartingAddress
) >> PAGE_SHIFT
;
387 * For some strange reason, it is perfectly valid to create a MAREA from 0x1000 to... 0x1000.
388 * In a normal OS/Memory Manager, this would be retarded, but ReactOS allows this (how it works
389 * I don't even want to know).
391 if (marea
->EndingAddress
!= marea
->StartingAddress
)
393 Vad
->EndingVpn
= PAGE_ROUND_DOWN((ULONG_PTR
)marea
->EndingAddress
- 1) >> PAGE_SHIFT
;
397 Vad
->EndingVpn
= Vad
->StartingVpn
;
399 Vad
->u
.VadFlags
.Spare
= 1;
400 Vad
->u
.VadFlags
.PrivateMemory
= 1;
401 Vad
->u
.VadFlags
.Protection
= MiMakeProtectionMask(marea
->Protect
);
402 MiInsertVad(Vad
, MmGetAddressSpaceOwner(AddressSpace
));
410 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
412 AddressSpace
->WorkingSetExpansionLinks
.Flink
= (PVOID
)marea
;
413 marea
->LeftChild
= marea
->RightChild
= marea
->Parent
= NULL
;
417 Node
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
420 DPRINT("marea->EndingAddress: %p Node->StartingAddress: %p\n",
421 marea
->EndingAddress
, Node
->StartingAddress
);
422 DPRINT("marea->StartingAddress: %p Node->EndingAddress: %p\n",
423 marea
->StartingAddress
, Node
->EndingAddress
);
424 ASSERT(marea
->EndingAddress
<= Node
->StartingAddress
||
425 marea
->StartingAddress
>= Node
->EndingAddress
);
426 ASSERT(marea
->StartingAddress
!= Node
->StartingAddress
);
430 if (marea
->StartingAddress
< Node
->StartingAddress
)
431 Node
= Node
->LeftChild
;
433 Node
= Node
->RightChild
;
440 MmRebalanceTree(AddressSpace
);
441 PreviousNode
= Node
->Parent
;
445 while (Node
!= NULL
);
447 marea
->LeftChild
= marea
->RightChild
= NULL
;
448 marea
->Parent
= PreviousNode
;
449 if (marea
->StartingAddress
< PreviousNode
->StartingAddress
)
450 PreviousNode
->LeftChild
= marea
;
452 PreviousNode
->RightChild
= marea
;
457 PMMSUPPORT AddressSpace
,
459 ULONG_PTR Granularity
)
461 ULONG_PTR LowestAddress
, HighestAddress
, Candidate
;
462 PMEMORY_AREA Root
, Node
;
464 /* Get the margins of the address space */
465 if (MmGetAddressSpaceOwner(AddressSpace
) != NULL
)
467 LowestAddress
= (ULONG_PTR
)MM_LOWEST_USER_ADDRESS
;
468 HighestAddress
= (ULONG_PTR
)MmHighestUserAddress
;
472 LowestAddress
= (ULONG_PTR
)MmSystemRangeStart
;
473 HighestAddress
= MAXULONG_PTR
;
476 /* Start with the lowest address */
477 Candidate
= LowestAddress
;
479 /* Check for overflow */
480 if ((Candidate
+ Length
) < Candidate
) return NULL
;
482 /* Get the root of the address space tree */
483 Root
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
485 /* Go to the node with lowest address in the tree. */
486 Node
= Root
? MmIterateFirstNode(Root
) : NULL
;
487 while (Node
&& ((ULONG_PTR
)Node
->EndingAddress
< LowestAddress
))
489 Node
= MmIterateNextNode(Node
);
492 /* Traverse the tree from low to high addresses */
493 while (Node
&& ((ULONG_PTR
)Node
->EndingAddress
< HighestAddress
))
495 /* Check if the memory area fits before the current node */
496 if ((ULONG_PTR
)Node
->StartingAddress
>= (Candidate
+ Length
))
498 DPRINT("MmFindGapBottomUp: %p\n", Candidate
);
499 ASSERT(Candidate
>= LowestAddress
);
500 return (PVOID
)Candidate
;
503 /* Calculate next possible adress above this node */
504 Candidate
= ALIGN_UP_BY((ULONG_PTR
)Node
->EndingAddress
, Granularity
);
506 /* Check for overflow */
507 if ((Candidate
+ Length
) < (ULONG_PTR
)Node
->EndingAddress
) return NULL
;
509 /* Go to the next higher node */
510 Node
= MmIterateNextNode(Node
);
513 /* Check if there is enough space after the last memory area. */
514 if ((Candidate
+ Length
) <= HighestAddress
)
516 DPRINT("MmFindGapBottomUp: %p\n", Candidate
);
517 ASSERT(Candidate
>= LowestAddress
);
518 return (PVOID
)Candidate
;
521 DPRINT("MmFindGapBottomUp: 0\n");
528 PMMSUPPORT AddressSpace
,
530 ULONG_PTR Granularity
)
532 ULONG_PTR LowestAddress
, HighestAddress
, Candidate
;
533 PMEMORY_AREA Root
, Node
;
535 /* Get the margins of the address space */
536 if (MmGetAddressSpaceOwner(AddressSpace
) != NULL
)
538 LowestAddress
= (ULONG_PTR
)MM_LOWEST_USER_ADDRESS
;
539 HighestAddress
= (ULONG_PTR
)MmHighestUserAddress
;
543 LowestAddress
= (ULONG_PTR
)MmSystemRangeStart
;
544 HighestAddress
= MAXULONG_PTR
;
547 /* Calculate the highest candidate */
548 Candidate
= ALIGN_DOWN_BY(HighestAddress
+ 1 - Length
, Granularity
);
550 /* Check for overflow. */
551 if (Candidate
> HighestAddress
) return NULL
;
553 /* Get the root of the address space tree */
554 Root
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
556 /* Go to the node with highest address in the tree. */
557 Node
= Root
? MmIterateLastNode(Root
) : NULL
;
558 while (Node
&& ((ULONG_PTR
)Node
->StartingAddress
> HighestAddress
))
560 Node
= MmIteratePrevNode(Node
);
563 /* Traverse the tree from high to low addresses */
564 while (Node
&& ((ULONG_PTR
)Node
->StartingAddress
> LowestAddress
))
566 /* Check if the memory area fits after the current node */
567 if ((ULONG_PTR
)Node
->EndingAddress
<= Candidate
)
569 DPRINT("MmFindGapTopDown: %p\n", Candidate
);
570 return (PVOID
)Candidate
;
573 /* Calculate next possible adress below this node */
574 Candidate
= ALIGN_DOWN_BY((ULONG_PTR
)Node
->StartingAddress
- Length
,
577 /* Check for overflow. */
578 if (Candidate
> (ULONG_PTR
)Node
->StartingAddress
)
581 /* Go to the next lower node */
582 Node
= MmIteratePrevNode(Node
);
585 /* Check if the last candidate is inside the given range */
586 if (Candidate
>= LowestAddress
)
588 DPRINT("MmFindGapTopDown: %p\n", Candidate
);
589 return (PVOID
)Candidate
;
592 DPRINT("MmFindGapTopDown: 0\n");
599 PMMSUPPORT AddressSpace
,
601 ULONG_PTR Granularity
,
605 return MmFindGapTopDown(AddressSpace
, Length
, Granularity
);
607 return MmFindGapBottomUp(AddressSpace
, Length
, Granularity
);
612 PMMSUPPORT AddressSpace
,
615 PMEMORY_AREA Node
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
616 PMEMORY_AREA RightNeighbour
= NULL
;
617 PVOID LowestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ? MM_LOWEST_USER_ADDRESS
: MmSystemRangeStart
;
618 PVOID HighestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ?
619 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
621 Address
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
623 if (LowestAddress
< MmSystemRangeStart
)
625 if (Address
>= MmSystemRangeStart
)
632 if (Address
< LowestAddress
)
640 if (Address
< Node
->StartingAddress
)
642 RightNeighbour
= Node
;
643 Node
= Node
->LeftChild
;
645 else if (Address
>= Node
->EndingAddress
)
647 Node
= Node
->RightChild
;
651 DPRINT("MmFindGapAtAddress: 0\n");
658 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
659 (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
);
660 return (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
;
664 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
665 (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
);
666 return (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
;
672 MiRemoveNode(IN PMMADDRESS_NODE Node
,
673 IN PMM_AVL_TABLE Table
);
676 * @name MmFreeMemoryArea
678 * Free an existing memory area.
680 * @param AddressSpace
681 * Address space to free the area from.
683 * Memory area we're about to free.
685 * Callback function for each freed page.
686 * @param FreePageContext
687 * Context passed to the callback function.
691 * @remarks Lock the address space before calling this function.
695 MiDeletePte(IN PMMPTE PointerPte
,
696 IN PVOID VirtualAddress
,
697 IN PEPROCESS CurrentProcess
,
698 IN PMMPTE PrototypePte
);
702 PMMSUPPORT AddressSpace
,
703 PMEMORY_AREA MemoryArea
,
704 PMM_FREE_PAGE_FUNC FreePage
,
705 PVOID FreePageContext
)
707 PMEMORY_AREA
*ParentReplace
;
711 if (MemoryArea
->Type
!= MEMORY_AREA_OWNED_BY_ARM3
)
713 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
714 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
716 if (Process
!= NULL
&&
717 Process
!= CurrentProcess
)
719 KeAttachProcess(&Process
->Pcb
);
722 EndAddress
= MM_ROUND_UP(MemoryArea
->EndingAddress
, PAGE_SIZE
);
723 for (Address
= (ULONG_PTR
)MemoryArea
->StartingAddress
;
724 Address
< (ULONG_PTR
)EndAddress
;
725 Address
+= PAGE_SIZE
)
727 BOOLEAN Dirty
= FALSE
;
728 SWAPENTRY SwapEntry
= 0;
731 if (MmIsPageSwapEntry(Process
, (PVOID
)Address
))
733 MmDeletePageFileMapping(Process
, (PVOID
)Address
, &SwapEntry
);
737 MmDeleteVirtualMapping(Process
, (PVOID
)Address
, FALSE
, &Dirty
, &Page
);
739 if (FreePage
!= NULL
)
741 FreePage(FreePageContext
, MemoryArea
, (PVOID
)Address
,
742 Page
, SwapEntry
, (BOOLEAN
)Dirty
);
744 #if (_MI_PAGING_LEVELS == 2)
745 /* Remove page table reference */
746 if((SwapEntry
|| Page
) && ((PVOID
)Address
< MmSystemRangeStart
))
748 ASSERT(AddressSpace
!= MmGetKernelAddressSpace());
749 MmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)]--;
750 ASSERT(MmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] < PTE_COUNT
);
751 if(MmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] == 0)
753 /* No PTE relies on this PDE. Release it */
754 KIRQL OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
755 PMMPDE PointerPde
= MiAddressToPde(Address
);
756 ASSERT(PointerPde
->u
.Hard
.Valid
== 1);
757 MiDeletePte(PointerPde
, MiPdeToPte(PointerPde
), Process
, NULL
);
758 ASSERT(PointerPde
->u
.Hard
.Valid
== 0);
759 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
765 if (Process
!= NULL
&&
766 Process
!= CurrentProcess
)
773 ASSERT(MemoryArea
->EndingAddress
< MmSystemRangeStart
);
774 ASSERT(MemoryArea
->Type
== MEMORY_AREA_VIRTUAL_MEMORY
|| MemoryArea
->Type
== MEMORY_AREA_SECTION_VIEW
);
776 /* MmCleanProcessAddressSpace might have removed it (and this would be MmDeleteProcessAdressSpace) */
777 ASSERT(((PMMVAD
)MemoryArea
->Vad
)->u
.VadFlags
.Spare
!= 0);
778 if (((PMMVAD
)MemoryArea
->Vad
)->u
.VadFlags
.Spare
== 1)
780 MiRemoveNode(MemoryArea
->Vad
, &Process
->VadRoot
);
783 ExFreePoolWithTag(MemoryArea
->Vad
, TAG_MVAD
);
784 MemoryArea
->Vad
= NULL
;
788 /* There must be no page ops in progress */
789 ASSERT(MemoryArea
->PageOpCount
== 0);
791 /* Remove the tree item. */
793 if (MemoryArea
->Parent
!= NULL
)
795 if (MemoryArea
->Parent
->LeftChild
== MemoryArea
)
796 ParentReplace
= &MemoryArea
->Parent
->LeftChild
;
798 ParentReplace
= &MemoryArea
->Parent
->RightChild
;
801 ParentReplace
= (PMEMORY_AREA
*)&AddressSpace
->WorkingSetExpansionLinks
.Flink
;
803 if (MemoryArea
->RightChild
== NULL
)
805 *ParentReplace
= MemoryArea
->LeftChild
;
806 if (MemoryArea
->LeftChild
)
807 MemoryArea
->LeftChild
->Parent
= MemoryArea
->Parent
;
811 if (MemoryArea
->RightChild
->LeftChild
== NULL
)
813 MemoryArea
->RightChild
->LeftChild
= MemoryArea
->LeftChild
;
814 if (MemoryArea
->LeftChild
)
815 MemoryArea
->LeftChild
->Parent
= MemoryArea
->RightChild
;
817 *ParentReplace
= MemoryArea
->RightChild
;
818 MemoryArea
->RightChild
->Parent
= MemoryArea
->Parent
;
822 PMEMORY_AREA LowestNode
;
824 LowestNode
= MemoryArea
->RightChild
->LeftChild
;
825 while (LowestNode
->LeftChild
!= NULL
)
826 LowestNode
= LowestNode
->LeftChild
;
828 LowestNode
->Parent
->LeftChild
= LowestNode
->RightChild
;
829 if (LowestNode
->RightChild
)
830 LowestNode
->RightChild
->Parent
= LowestNode
->Parent
;
832 LowestNode
->LeftChild
= MemoryArea
->LeftChild
;
833 if (MemoryArea
->LeftChild
)
834 MemoryArea
->LeftChild
->Parent
= LowestNode
;
836 LowestNode
->RightChild
= MemoryArea
->RightChild
;
837 MemoryArea
->RightChild
->Parent
= LowestNode
;
839 *ParentReplace
= LowestNode
;
840 LowestNode
->Parent
= MemoryArea
->Parent
;
845 ExFreePoolWithTag(MemoryArea
, TAG_MAREA
);
847 DPRINT("MmFreeMemoryAreaByNode() succeeded\n");
849 return STATUS_SUCCESS
;
853 * @name MmCreateMemoryArea
855 * Create a memory area.
857 * @param AddressSpace
858 * Address space to create the area in.
860 * Type of the memory area.
862 * Base address for the memory area we're about the create. On
863 * input it contains either 0 (auto-assign address) or preferred
864 * address. On output it contains the starting address of the
865 * newly created area.
867 * Length of the area to allocate.
869 * Protection attributes for the memory area.
871 * Receives a pointer to the memory area on successful exit.
875 * @remarks Lock the address space before calling this function.
879 MmCreateMemoryArea(PMMSUPPORT AddressSpace
,
884 PMEMORY_AREA
*Result
,
885 BOOLEAN FixedAddress
,
886 ULONG AllocationFlags
,
887 PHYSICAL_ADDRESS BoundaryAddressMultiple
)
892 PMEMORY_AREA MemoryArea
;
894 DPRINT("MmCreateMemoryArea(Type 0x%lx, BaseAddress %p, "
895 "*BaseAddress %p, Length %p, AllocationFlags %x, "
896 "FixedAddress %x, Result %p)\n",
897 Type
, BaseAddress
, *BaseAddress
, Length
, AllocationFlags
,
898 FixedAddress
, Result
);
900 Granularity
= (MEMORY_AREA_VIRTUAL_MEMORY
== Type
? MM_VIRTMEM_GRANULARITY
: PAGE_SIZE
);
901 if ((*BaseAddress
) == 0 && !FixedAddress
)
903 tmpLength
= (ULONG_PTR
)MM_ROUND_UP(Length
, Granularity
);
904 *BaseAddress
= MmFindGap(AddressSpace
,
907 (AllocationFlags
& MEM_TOP_DOWN
) == MEM_TOP_DOWN
);
908 if ((*BaseAddress
) == 0)
910 DPRINT("No suitable gap\n");
911 return STATUS_NO_MEMORY
;
916 tmpLength
= Length
+ ((ULONG_PTR
) *BaseAddress
917 - (ULONG_PTR
) MM_ROUND_DOWN(*BaseAddress
, Granularity
));
918 tmpLength
= (ULONG_PTR
)MM_ROUND_UP(tmpLength
, Granularity
);
919 *BaseAddress
= MM_ROUND_DOWN(*BaseAddress
, Granularity
);
921 if (!MmGetAddressSpaceOwner(AddressSpace
) && *BaseAddress
< MmSystemRangeStart
)
923 return STATUS_ACCESS_VIOLATION
;
926 if (MmGetAddressSpaceOwner(AddressSpace
) &&
927 (ULONG_PTR
)(*BaseAddress
) + tmpLength
> (ULONG_PTR
)MmSystemRangeStart
)
929 DPRINT("Memory area for user mode address space exceeds MmSystemRangeStart\n");
930 return STATUS_ACCESS_VIOLATION
;
933 if (BoundaryAddressMultiple
.QuadPart
!= 0)
935 EndAddress
= ((char*)(*BaseAddress
)) + tmpLength
-1;
936 ASSERT(((ULONG_PTR
)*BaseAddress
/BoundaryAddressMultiple
.QuadPart
) == ((DWORD_PTR
)EndAddress
/BoundaryAddressMultiple
.QuadPart
));
939 if (MmLocateMemoryAreaByRegion(AddressSpace
,
943 DPRINT("Memory area already occupied\n");
944 return STATUS_CONFLICTING_ADDRESSES
;
949 // Is this a static memory area?
951 if (Type
& MEMORY_AREA_STATIC
)
954 // Use the static array instead of the pool
956 ASSERT(MiStaticMemoryAreaCount
< MI_STATIC_MEMORY_AREAS
);
957 MemoryArea
= &MiStaticMemoryAreas
[MiStaticMemoryAreaCount
++];
958 Type
&= ~MEMORY_AREA_STATIC
;
963 // Allocate the memory area from nonpaged pool
965 MemoryArea
= ExAllocatePoolWithTag(NonPagedPool
,
970 if (!MemoryArea
) return STATUS_NO_MEMORY
;
972 RtlZeroMemory(MemoryArea
, sizeof(MEMORY_AREA
));
973 MemoryArea
->Type
= Type
;
974 MemoryArea
->StartingAddress
= *BaseAddress
;
975 MemoryArea
->EndingAddress
= (PVOID
)((ULONG_PTR
)*BaseAddress
+ tmpLength
);
976 MemoryArea
->Protect
= Protect
;
977 MemoryArea
->Flags
= AllocationFlags
;
978 //MemoryArea->LockCount = 0;
979 MemoryArea
->PageOpCount
= 0;
980 MemoryArea
->DeleteInProgress
= FALSE
;
982 MmInsertMemoryArea(AddressSpace
, MemoryArea
);
984 *Result
= MemoryArea
;
986 DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress
);
987 return STATUS_SUCCESS
;
991 MmMapMemoryArea(PVOID BaseAddress
,
999 ASSERT(((ULONG_PTR
)BaseAddress
% PAGE_SIZE
) == 0);
1001 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1005 Status
= MmRequestPageMemoryConsumer(Consumer
, TRUE
, &Page
);
1006 if (!NT_SUCCESS(Status
))
1008 DPRINT1("Unable to allocate page\n");
1009 KeBugCheck(MEMORY_MANAGEMENT
);
1011 Status
= MmCreateVirtualMapping (NULL
,
1012 (PVOID
)((ULONG_PTR
)BaseAddress
+ (i
* PAGE_SIZE
)),
1016 if (!NT_SUCCESS(Status
))
1018 DPRINT1("Unable to create virtual mapping\n");
1019 KeBugCheck(MEMORY_MANAGEMENT
);
1026 MmDeleteProcessAddressSpace2(IN PEPROCESS Process
);
1030 MmDeleteProcessAddressSpace(PEPROCESS Process
)
1033 PMEMORY_AREA MemoryArea
;
1035 DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process
,
1036 Process
->ImageFileName
);
1039 RemoveEntryList(&Process
->MmProcessLinks
);
1041 MmLockAddressSpace(&Process
->Vm
);
1043 while ((MemoryArea
= (PMEMORY_AREA
)Process
->Vm
.WorkingSetExpansionLinks
.Flink
) != NULL
)
1045 switch (MemoryArea
->Type
)
1047 case MEMORY_AREA_SECTION_VIEW
:
1048 Address
= (PVOID
)MemoryArea
->StartingAddress
;
1049 MmUnlockAddressSpace(&Process
->Vm
);
1050 MmUnmapViewOfSection(Process
, Address
);
1051 MmLockAddressSpace(&Process
->Vm
);
1054 case MEMORY_AREA_VIRTUAL_MEMORY
:
1055 MmFreeVirtualMemory(Process
, MemoryArea
);
1058 case MEMORY_AREA_OWNED_BY_ARM3
:
1059 MmFreeMemoryArea(&Process
->Vm
,
1066 KeBugCheck(MEMORY_MANAGEMENT
);
1070 #if (_MI_PAGING_LEVELS == 2)
1074 /* Attach to Process */
1075 KeAttachProcess(&Process
->Pcb
);
1077 /* Acquire PFN lock */
1078 OldIrql
= KeAcquireQueuedSpinLock(LockQueuePfnLock
);
1080 for(Address
= MI_LOWEST_VAD_ADDRESS
;
1081 Address
< MM_HIGHEST_VAD_ADDRESS
;
1082 Address
=(PVOID
)((ULONG_PTR
)Address
+ (PAGE_SIZE
* PTE_COUNT
)))
1084 /* At this point all references should be dead */
1085 ASSERT(MmWorkingSetList
->UsedPageTableEntries
[MiGetPdeOffset(Address
)] == 0);
1086 pointerPde
= MiAddressToPde(Address
);
1087 /* Unlike in ARM3, we don't necesarrily free the PDE page as soon as reference reaches 0,
1088 * so we must clean up a bit when process closes */
1089 if(pointerPde
->u
.Hard
.Valid
)
1090 MiDeletePte(pointerPde
, MiPdeToPte(pointerPde
), Process
, NULL
);
1091 ASSERT(pointerPde
->u
.Hard
.Valid
== 0);
1094 KeReleaseQueuedSpinLock(LockQueuePfnLock
, OldIrql
);
1101 MmUnlockAddressSpace(&Process
->Vm
);
1103 DPRINT("Finished MmReleaseMmInfo()\n");
1104 MmDeleteProcessAddressSpace2(Process
);
1105 return(STATUS_SUCCESS
);