3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/mm/marea.c
6 * PURPOSE: Implements memory areas
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS *******************************************************************/
19 #define TAG_MAREA TAG('M', 'A', 'R', 'E')
21 /* #define VALIDATE_MEMORY_AREAS */
23 /* FUNCTIONS *****************************************************************/
26 * @name MmIterateFirstNode
29 * Head node of the MEMORY_AREA tree.
31 * @return The leftmost MEMORY_AREA node (ie. the one with lowest
35 static PMEMORY_AREA
MmIterateFirstNode(PMEMORY_AREA Node
)
37 while (Node
->LeftChild
!= NULL
)
38 Node
= Node
->LeftChild
;
44 * @name MmIterateNextNode
47 * Current node in the tree.
49 * @return Next node in the tree (sorted by address).
52 static PMEMORY_AREA
MmIterateNextNode(PMEMORY_AREA Node
)
54 if (Node
->RightChild
!= NULL
)
56 Node
= Node
->RightChild
;
57 while (Node
->LeftChild
!= NULL
)
58 Node
= Node
->LeftChild
;
62 PMEMORY_AREA TempNode
= NULL
;
66 /* Check if we're at the end of tree. */
67 if (Node
->Parent
== NULL
)
73 while (TempNode
== Node
->RightChild
);
79 * @name MmIterateFirstNode
82 * Head node of the MEMORY_AREA tree.
84 * @return The rightmost MEMORY_AREA node (ie. the one with highest
88 static PMEMORY_AREA
MmIterateLastNode(PMEMORY_AREA Node
)
90 while (Node
->RightChild
!= NULL
)
91 Node
= Node
->RightChild
;
97 * @name MmIterateNextNode
100 * Current node in the tree.
102 * @return Previous node in the tree (sorted by address).
105 static PMEMORY_AREA
MmIteratePrevNode(PMEMORY_AREA Node
)
107 if (Node
->LeftChild
!= NULL
)
109 Node
= Node
->LeftChild
;
110 while (Node
->RightChild
!= NULL
)
111 Node
= Node
->RightChild
;
115 PMEMORY_AREA TempNode
= NULL
;
119 /* Check if we're at the end of tree. */
120 if (Node
->Parent
== NULL
)
126 while (TempNode
== Node
->LeftChild
);
131 #ifdef VALIDATE_MEMORY_AREAS
132 static VOID
MmVerifyMemoryAreas(PMADDRESS_SPACE AddressSpace
)
136 ASSERT(AddressSpace
!= NULL
);
138 /* Special case for empty tree. */
139 if (AddressSpace
->MemoryAreaRoot
== NULL
)
142 /* Traverse the tree from left to right. */
143 for (Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
145 Node
= MmIterateNextNode(Node
))
147 /* FiN: The starting address can be NULL if someone explicitely asks
148 * for NULL address. */
149 ASSERT(Node
->StartingAddress
>= AddressSpace
->LowestAddress
||
150 Node
->StartingAddress
== NULL
);
151 ASSERT(Node
->EndingAddress
>= Node
->StartingAddress
);
155 #define MmVerifyMemoryAreas(x)
159 MmDumpMemoryAreas(PMADDRESS_SPACE AddressSpace
)
163 DbgPrint("MmDumpMemoryAreas()\n");
165 /* Special case for empty tree. */
166 if (AddressSpace
->MemoryAreaRoot
== NULL
)
169 /* Traverse the tree from left to right. */
170 for (Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
172 Node
= MmIterateNextNode(Node
))
174 DbgPrint("Start %p End %p Attributes %x\n",
175 Node
->StartingAddress
, Node
->EndingAddress
,
179 DbgPrint("Finished MmDumpMemoryAreas()\n");
183 MmLocateMemoryAreaByAddress(
184 PMADDRESS_SPACE AddressSpace
,
187 PMEMORY_AREA Node
= AddressSpace
->MemoryAreaRoot
;
189 DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
190 AddressSpace
, Address
);
192 if (!(KdDebugState
& KD_DEBUG_SCREEN
))
193 MmVerifyMemoryAreas(AddressSpace
);
197 if (Address
< Node
->StartingAddress
)
198 Node
= Node
->LeftChild
;
199 else if (Address
>= Node
->EndingAddress
)
200 Node
= Node
->RightChild
;
203 DPRINT("MmLocateMemoryAreaByAddress(%p): %p [%p - %p]\n",
204 Address
, Node
, Node
->StartingAddress
, Node
->EndingAddress
);
209 DPRINT("MmLocateMemoryAreaByAddress(%p): 0\n", Address
);
214 MmLocateMemoryAreaByRegion(
215 PMADDRESS_SPACE AddressSpace
,
220 PVOID Extent
= (PVOID
)((ULONG_PTR
)Address
+ Length
);
222 MmVerifyMemoryAreas(AddressSpace
);
224 /* Special case for empty tree. */
225 if (AddressSpace
->MemoryAreaRoot
== NULL
)
228 /* Traverse the tree from left to right. */
229 for (Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
231 Node
= MmIterateNextNode(Node
))
233 if (Node
->StartingAddress
>= Address
&&
234 Node
->StartingAddress
< Extent
)
236 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
237 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
238 Node
->EndingAddress
);
241 if (Node
->EndingAddress
> Address
&&
242 Node
->EndingAddress
< Extent
)
244 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
245 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
246 Node
->EndingAddress
);
249 if (Node
->StartingAddress
<= Address
&&
250 Node
->EndingAddress
>= Extent
)
252 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
253 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
254 Node
->EndingAddress
);
257 if (Node
->StartingAddress
>= Extent
)
259 DPRINT("Finished MmLocateMemoryAreaByRegion() = NULL\n");
268 * @name MmCompressHelper
270 * This is helper of MmRebalanceTree. Performs a compression transformation
271 * count times, starting at root.
276 PMADDRESS_SPACE AddressSpace
,
279 PMEMORY_AREA Root
= NULL
;
280 PMEMORY_AREA Red
= AddressSpace
->MemoryAreaRoot
;
281 PMEMORY_AREA Black
= Red
->LeftChild
;
286 Root
->LeftChild
= Black
;
288 AddressSpace
->MemoryAreaRoot
= Black
;
289 Black
->Parent
= Root
;
290 Red
->LeftChild
= Black
->RightChild
;
291 if (Black
->RightChild
)
292 Black
->RightChild
->Parent
= Red
;
293 Black
->RightChild
= Red
;
299 Red
= Root
->LeftChild
;
300 Black
= Red
->LeftChild
;
306 * @name MmRebalanceTree
308 * Rebalance a memory area tree using the Tree->Vine->Balanced Tree
309 * method described in libavl documentation in chapter 4.12.
310 * (http://www.stanford.edu/~blp/avl/libavl.html/)
315 PMADDRESS_SPACE AddressSpace
)
317 PMEMORY_AREA PreviousNode
;
318 PMEMORY_AREA CurrentNode
;
319 PMEMORY_AREA TempNode
;
321 ULONG Vine
; /* Number of nodes in main vine. */
322 ULONG Leaves
; /* Nodes in incomplete bottom level, if any. */
323 INT Height
; /* Height of produced balanced tree. */
325 /* Transform the tree into Vine. */
328 CurrentNode
= AddressSpace
->MemoryAreaRoot
;
329 while (CurrentNode
!= NULL
)
331 if (CurrentNode
->RightChild
== NULL
)
333 PreviousNode
= CurrentNode
;
334 CurrentNode
= CurrentNode
->LeftChild
;
339 TempNode
= CurrentNode
->RightChild
;
341 CurrentNode
->RightChild
= TempNode
->LeftChild
;
342 if (TempNode
->LeftChild
)
343 TempNode
->LeftChild
->Parent
= CurrentNode
;
345 TempNode
->LeftChild
= CurrentNode
;
346 CurrentNode
->Parent
= TempNode
;
348 CurrentNode
= TempNode
;
350 if (PreviousNode
!= NULL
)
351 PreviousNode
->LeftChild
= TempNode
;
353 AddressSpace
->MemoryAreaRoot
= TempNode
;
354 TempNode
->Parent
= PreviousNode
;
358 /* Transform Vine back into a balanced tree. */
360 Leaves
= NodeCount
+ 1;
363 ULONG Next
= Leaves
& (Leaves
- 1);
368 Leaves
= NodeCount
+ 1 - Leaves
;
370 MmCompressHelper(AddressSpace
, Leaves
);
372 Vine
= NodeCount
- Leaves
;
373 Height
= 1 + (Leaves
> 0);
376 MmCompressHelper(AddressSpace
, Vine
/ 2);
384 PMADDRESS_SPACE AddressSpace
,
388 PMEMORY_AREA PreviousNode
;
391 MmVerifyMemoryAreas(AddressSpace
);
393 if (AddressSpace
->MemoryAreaRoot
== NULL
)
395 AddressSpace
->MemoryAreaRoot
= marea
;
396 marea
->LeftChild
= marea
->RightChild
= marea
->Parent
= NULL
;
400 Node
= AddressSpace
->MemoryAreaRoot
;
403 DPRINT("marea->EndingAddress: %p Node->StartingAddress: %p\n",
404 marea
->EndingAddress
, Node
->StartingAddress
);
405 DPRINT("marea->StartingAddress: %p Node->EndingAddress: %p\n",
406 marea
->StartingAddress
, Node
->EndingAddress
);
407 ASSERT(marea
->EndingAddress
<= Node
->StartingAddress
||
408 marea
->StartingAddress
>= Node
->EndingAddress
);
409 ASSERT(marea
->StartingAddress
!= Node
->StartingAddress
);
413 if (marea
->StartingAddress
< Node
->StartingAddress
)
414 Node
= Node
->LeftChild
;
416 Node
= Node
->RightChild
;
423 MmRebalanceTree(AddressSpace
);
424 PreviousNode
= Node
->Parent
;
428 while (Node
!= NULL
);
430 marea
->LeftChild
= marea
->RightChild
= NULL
;
431 marea
->Parent
= PreviousNode
;
432 if (marea
->StartingAddress
< PreviousNode
->StartingAddress
)
433 PreviousNode
->LeftChild
= marea
;
435 PreviousNode
->RightChild
= marea
;
440 PMADDRESS_SPACE AddressSpace
,
442 ULONG_PTR Granularity
)
444 PVOID HighestAddress
= AddressSpace
->LowestAddress
< (PVOID
)KERNEL_BASE
?
445 (PVOID
)(KERNEL_BASE
- 1) : (PVOID
)MAXULONG_PTR
;
446 PVOID AlignedAddress
;
448 PMEMORY_AREA FirstNode
;
449 PMEMORY_AREA PreviousNode
;
451 MmVerifyMemoryAreas(AddressSpace
);
453 DPRINT("LowestAddress: %p HighestAddress: %p\n",
454 AddressSpace
->LowestAddress
, HighestAddress
);
456 AlignedAddress
= MM_ROUND_UP(AddressSpace
->LowestAddress
, Granularity
);
458 /* Special case for empty tree. */
459 if (AddressSpace
->MemoryAreaRoot
== NULL
)
461 if ((ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
463 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
464 return AlignedAddress
;
466 DPRINT("MmFindGapBottomUp: 0\n");
470 /* Go to the node with lowest address in the tree. */
471 FirstNode
= Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
473 /* Traverse the tree from left to right. */
477 Node
= MmIterateNextNode(Node
);
481 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
482 if (Node
->StartingAddress
> AlignedAddress
&&
483 (ULONG_PTR
)Node
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
485 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
486 return AlignedAddress
;
492 /* Check if there is enough space after the last memory area. */
493 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
494 if ((ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
496 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
497 return AlignedAddress
;
500 /* Check if there is enough space before the first memory area. */
501 AlignedAddress
= MM_ROUND_UP(AddressSpace
->LowestAddress
, Granularity
);
502 if (FirstNode
->StartingAddress
> AlignedAddress
&&
503 (ULONG_PTR
)FirstNode
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
505 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
506 return AlignedAddress
;
509 DPRINT("MmFindGapBottomUp: 0\n");
516 PMADDRESS_SPACE AddressSpace
,
518 ULONG_PTR Granularity
)
520 PVOID HighestAddress
= AddressSpace
->LowestAddress
< (PVOID
)KERNEL_BASE
?
521 (PVOID
)(KERNEL_BASE
- 1) : (PVOID
)MAXULONG_PTR
;
522 PVOID AlignedAddress
;
524 PMEMORY_AREA PreviousNode
;
526 MmVerifyMemoryAreas(AddressSpace
);
528 DPRINT("LowestAddress: %p HighestAddress: %p\n",
529 AddressSpace
->LowestAddress
, HighestAddress
);
531 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)HighestAddress
- Length
+ 1, Granularity
);
533 /* Check for overflow. */
534 if (AlignedAddress
> HighestAddress
)
537 /* Special case for empty tree. */
538 if (AddressSpace
->MemoryAreaRoot
== NULL
)
540 if (AlignedAddress
>= (PVOID
)AddressSpace
->LowestAddress
)
542 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
543 return AlignedAddress
;
545 DPRINT("MmFindGapTopDown: 0\n");
549 /* Go to the node with highest address in the tree. */
550 Node
= MmIterateLastNode(AddressSpace
->MemoryAreaRoot
);
552 /* Check if there is enough space after the last memory area. */
553 if (Node
->EndingAddress
<= AlignedAddress
)
555 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
556 return AlignedAddress
;
559 /* Traverse the tree from left to right. */
563 Node
= MmIteratePrevNode(Node
);
567 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
569 /* Check for overflow. */
570 if (AlignedAddress
> PreviousNode
->StartingAddress
)
573 if (Node
->EndingAddress
<= AlignedAddress
)
575 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
576 return AlignedAddress
;
582 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
584 /* Check for overflow. */
585 if (AlignedAddress
> PreviousNode
->StartingAddress
)
588 if (AlignedAddress
>= (PVOID
)AddressSpace
->LowestAddress
)
590 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
591 return AlignedAddress
;
594 DPRINT("MmFindGapTopDown: 0\n");
601 PMADDRESS_SPACE AddressSpace
,
603 ULONG_PTR Granularity
,
607 return MmFindGapTopDown(AddressSpace
, Length
, Granularity
);
609 return MmFindGapBottomUp(AddressSpace
, Length
, Granularity
);
614 PMADDRESS_SPACE AddressSpace
,
617 PMEMORY_AREA Node
= AddressSpace
->MemoryAreaRoot
;
618 PMEMORY_AREA RightNeighbour
= NULL
;
619 PVOID HighestAddress
= AddressSpace
->LowestAddress
< (PVOID
)KERNEL_BASE
?
620 (PVOID
)(KERNEL_BASE
- 1) : (PVOID
)MAXULONG_PTR
;
622 MmVerifyMemoryAreas(AddressSpace
);
624 Address
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
626 if (AddressSpace
->LowestAddress
< (PVOID
)KERNEL_BASE
)
628 if (Address
>= (PVOID
)KERNEL_BASE
)
635 if (Address
< AddressSpace
->LowestAddress
)
643 if (Address
< Node
->StartingAddress
)
645 RightNeighbour
= Node
;
646 Node
= Node
->LeftChild
;
648 else if (Address
>= Node
->EndingAddress
)
650 Node
= Node
->RightChild
;
654 DPRINT("MmFindGapAtAddress: 0\n");
661 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
662 (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
);
663 return (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
;
667 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
668 (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
);
669 return (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
;
674 * @name MmInitMemoryAreas
676 * Initialize the memory area list implementation.
679 NTSTATUS INIT_FUNCTION
680 MmInitMemoryAreas(VOID
)
682 DPRINT("MmInitMemoryAreas()\n",0);
683 return(STATUS_SUCCESS
);
688 * @name MmFreeMemoryArea
690 * Free an existing memory area.
692 * @param AddressSpace
693 * Address space to free the area from.
695 * Memory area we're about to free.
697 * Callback function for each freed page.
698 * @param FreePageContext
699 * Context passed to the callback function.
703 * @remarks Lock the address space before calling this function.
708 PMADDRESS_SPACE AddressSpace
,
709 PMEMORY_AREA MemoryArea
,
710 PMM_FREE_PAGE_FUNC FreePage
,
711 PVOID FreePageContext
)
713 PMEMORY_AREA
*ParentReplace
;
716 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
718 if (AddressSpace
->Process
!= NULL
&&
719 AddressSpace
->Process
!= CurrentProcess
)
721 KeAttachProcess(&AddressSpace
->Process
->Pcb
);
724 EndAddress
= MM_ROUND_UP(MemoryArea
->EndingAddress
, PAGE_SIZE
);
725 for (Address
= (ULONG_PTR
)MemoryArea
->StartingAddress
;
726 Address
< (ULONG_PTR
)EndAddress
;
727 Address
+= PAGE_SIZE
)
729 if (MemoryArea
->Type
== MEMORY_AREA_IO_MAPPING
)
731 MmRawDeleteVirtualMapping((PVOID
)Address
);
736 SWAPENTRY SwapEntry
= 0;
739 if (MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)Address
))
741 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)Address
, &SwapEntry
);
745 MmDeleteVirtualMapping(AddressSpace
->Process
, (PVOID
)Address
, FALSE
, &Dirty
, &Page
);
747 if (FreePage
!= NULL
)
749 FreePage(FreePageContext
, MemoryArea
, (PVOID
)Address
,
750 Page
, SwapEntry
, (BOOLEAN
)Dirty
);
755 if (AddressSpace
->Process
!= NULL
&&
756 AddressSpace
->Process
!= CurrentProcess
)
761 /* Remove the tree item. */
763 if (MemoryArea
->Parent
!= NULL
)
765 if (MemoryArea
->Parent
->LeftChild
== MemoryArea
)
766 ParentReplace
= &MemoryArea
->Parent
->LeftChild
;
768 ParentReplace
= &MemoryArea
->Parent
->RightChild
;
771 ParentReplace
= &AddressSpace
->MemoryAreaRoot
;
773 if (MemoryArea
->RightChild
== NULL
)
775 *ParentReplace
= MemoryArea
->LeftChild
;
776 if (MemoryArea
->LeftChild
)
777 MemoryArea
->LeftChild
->Parent
= MemoryArea
->Parent
;
781 if (MemoryArea
->RightChild
->LeftChild
== NULL
)
783 MemoryArea
->RightChild
->LeftChild
= MemoryArea
->LeftChild
;
784 if (MemoryArea
->LeftChild
)
785 MemoryArea
->LeftChild
->Parent
= MemoryArea
->RightChild
;
787 *ParentReplace
= MemoryArea
->RightChild
;
788 MemoryArea
->RightChild
->Parent
= MemoryArea
->Parent
;
792 PMEMORY_AREA LowestNode
;
794 LowestNode
= MemoryArea
->RightChild
->LeftChild
;
795 while (LowestNode
->LeftChild
!= NULL
)
796 LowestNode
= LowestNode
->LeftChild
;
798 LowestNode
->Parent
->LeftChild
= LowestNode
->RightChild
;
799 if (LowestNode
->RightChild
)
800 LowestNode
->RightChild
->Parent
= LowestNode
->Parent
;
802 LowestNode
->LeftChild
= MemoryArea
->LeftChild
;
803 if (MemoryArea
->LeftChild
)
804 MemoryArea
->LeftChild
->Parent
= LowestNode
;
806 LowestNode
->RightChild
= MemoryArea
->RightChild
;
807 MemoryArea
->RightChild
->Parent
= LowestNode
;
809 *ParentReplace
= LowestNode
;
810 LowestNode
->Parent
= MemoryArea
->Parent
;
815 ExFreePool(MemoryArea
);
817 DPRINT("MmFreeMemoryAreaByNode() succeeded\n");
819 return STATUS_SUCCESS
;
823 * @name MmFreeMemoryAreaByPtr
825 * Free an existing memory area given a pointer inside it.
827 * @param AddressSpace
828 * Address space to free the area from.
830 * Address in the memory area we're about to free.
832 * Callback function for each freed page.
833 * @param FreePageContext
834 * Context passed to the callback function.
838 * @see MmFreeMemoryArea
840 * @todo Should we require the BaseAddress to be really the starting
841 * address of the memory area or is the current relaxed check
842 * (BaseAddress can point anywhere in the memory area) acceptable?
844 * @remarks Lock the address space before calling this function.
848 MmFreeMemoryAreaByPtr(
849 PMADDRESS_SPACE AddressSpace
,
851 PMM_FREE_PAGE_FUNC FreePage
,
852 PVOID FreePageContext
)
854 PMEMORY_AREA MemoryArea
;
856 DPRINT("MmFreeMemoryArea(AddressSpace %p, BaseAddress %p, "
857 "FreePageContext %p)\n", AddressSpace
, BaseAddress
,
860 MmVerifyMemoryAreas(AddressSpace
);
862 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
864 if (MemoryArea
== NULL
)
867 return(STATUS_UNSUCCESSFUL
);
870 return MmFreeMemoryArea(AddressSpace
, MemoryArea
, FreePage
, FreePageContext
);
874 * @name MmCreateMemoryArea
876 * Create a memory area.
878 * @param AddressSpace
879 * Address space to create the area in.
881 * Type of the memory area.
883 * Base address for the memory area we're about the create. On
884 * input it contains either 0 (auto-assign address) or preferred
885 * address. On output it contains the starting address of the
886 * newly created area.
888 * Length of the area to allocate.
890 * Protection attributes for the memory area.
892 * Receives a pointer to the memory area on successful exit.
896 * @remarks Lock the address space before calling this function.
900 MmCreateMemoryArea(PEPROCESS Process
,
901 PMADDRESS_SPACE AddressSpace
,
906 PMEMORY_AREA
*Result
,
907 BOOLEAN FixedAddress
,
909 PHYSICAL_ADDRESS BoundaryAddressMultiple
)
914 PMEMORY_AREA MemoryArea
;
916 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
917 "*BaseAddress %p, Length %p, Attributes %x, TopDown: %x, "
918 "FixedAddress %x, Result %p)\n",
919 Type
, BaseAddress
, *BaseAddress
, Length
, Attributes
, TopDown
,
920 FixedAddress
, Result
);
922 MmVerifyMemoryAreas(AddressSpace
);
924 Granularity
= (MEMORY_AREA_VIRTUAL_MEMORY
== Type
? MM_VIRTMEM_GRANULARITY
: PAGE_SIZE
);
925 if ((*BaseAddress
) == 0 && !FixedAddress
)
927 tmpLength
= PAGE_ROUND_UP(Length
);
928 *BaseAddress
= MmFindGap(AddressSpace
,
932 if ((*BaseAddress
) == 0)
934 DPRINT("No suitable gap\n");
935 return STATUS_NO_MEMORY
;
940 tmpLength
= Length
+ ((ULONG_PTR
) *BaseAddress
941 - (ULONG_PTR
) MM_ROUND_DOWN(*BaseAddress
, Granularity
));
942 *BaseAddress
= MM_ROUND_DOWN(*BaseAddress
, Granularity
);
944 if (AddressSpace
->LowestAddress
== (PVOID
)KERNEL_BASE
&&
945 *BaseAddress
< (PVOID
)KERNEL_BASE
)
948 return STATUS_ACCESS_VIOLATION
;
951 if (AddressSpace
->LowestAddress
< (PVOID
)KERNEL_BASE
&&
952 (ULONG_PTR
)(*BaseAddress
) + tmpLength
> KERNEL_BASE
)
955 return STATUS_ACCESS_VIOLATION
;
958 if (BoundaryAddressMultiple
.QuadPart
!= 0)
960 EndAddress
= ((char*)(*BaseAddress
)) + tmpLength
-1;
961 ASSERT(((ULONG_PTR
)*BaseAddress
/BoundaryAddressMultiple
.QuadPart
) == ((DWORD_PTR
)EndAddress
/BoundaryAddressMultiple
.QuadPart
));
964 if (MmLocateMemoryAreaByRegion(AddressSpace
,
968 DPRINT("Memory area already occupied\n");
969 return STATUS_CONFLICTING_ADDRESSES
;
973 MemoryArea
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MEMORY_AREA
),
975 RtlZeroMemory(MemoryArea
, sizeof(MEMORY_AREA
));
976 MemoryArea
->Type
= Type
;
977 MemoryArea
->StartingAddress
= *BaseAddress
;
978 MemoryArea
->EndingAddress
= (PVOID
)((ULONG_PTR
)*BaseAddress
+ tmpLength
);
979 MemoryArea
->Attributes
= Attributes
;
980 MemoryArea
->LockCount
= 0;
981 MemoryArea
->Process
= Process
;
982 MemoryArea
->PageOpCount
= 0;
983 MemoryArea
->DeleteInProgress
= FALSE
;
985 MmInsertMemoryArea(AddressSpace
, MemoryArea
);
987 *Result
= MemoryArea
;
989 DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress
);
990 return STATUS_SUCCESS
;
995 MmReleaseMemoryAreaIfDecommitted(PEPROCESS Process
,
996 PMADDRESS_SPACE AddressSpace
,
999 PMEMORY_AREA MemoryArea
;
1004 MmVerifyMemoryAreas(AddressSpace
);
1006 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1007 if (MemoryArea
!= NULL
)
1009 Entry
= MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
.Flink
;
1011 while (Reserved
&& Entry
!= &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
)
1013 Region
= CONTAINING_RECORD(Entry
, MM_REGION
, RegionListEntry
);
1014 Reserved
= (MEM_RESERVE
== Region
->Type
);
1015 Entry
= Entry
->Flink
;
1020 MmFreeVirtualMemory(Process
, MemoryArea
);