3 * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/marea.c
22 * PURPOSE: Implements memory areas
24 * PROGRAMMERS: Rex Jolliff
34 * Thomas Weidenmueller
35 * Gunnar Andre' Dalsnes
43 /* INCLUDES *****************************************************************/
47 #include <internal/debug.h>
49 #if defined (ALLOC_PRAGMA)
50 #pragma alloc_text(INIT, MmInitMemoryAreas)
53 /* #define VALIDATE_MEMORY_AREAS */
55 /* FUNCTIONS *****************************************************************/
58 * @name MmIterateFirstNode
61 * Head node of the MEMORY_AREA tree.
63 * @return The leftmost MEMORY_AREA node (ie. the one with lowest
67 static PMEMORY_AREA
MmIterateFirstNode(PMEMORY_AREA Node
)
69 while (Node
->LeftChild
!= NULL
)
70 Node
= Node
->LeftChild
;
76 * @name MmIterateNextNode
79 * Current node in the tree.
81 * @return Next node in the tree (sorted by address).
84 static PMEMORY_AREA
MmIterateNextNode(PMEMORY_AREA Node
)
86 if (Node
->RightChild
!= NULL
)
88 Node
= Node
->RightChild
;
89 while (Node
->LeftChild
!= NULL
)
90 Node
= Node
->LeftChild
;
94 PMEMORY_AREA TempNode
= NULL
;
98 /* Check if we're at the end of tree. */
99 if (Node
->Parent
== NULL
)
105 while (TempNode
== Node
->RightChild
);
111 * @name MmIterateLastNode
114 * Head node of the MEMORY_AREA tree.
116 * @return The rightmost MEMORY_AREA node (ie. the one with highest
120 static PMEMORY_AREA
MmIterateLastNode(PMEMORY_AREA Node
)
122 while (Node
->RightChild
!= NULL
)
123 Node
= Node
->RightChild
;
129 * @name MmIteratePreviousNode
132 * Current node in the tree.
134 * @return Previous node in the tree (sorted by address).
137 static PMEMORY_AREA
MmIteratePrevNode(PMEMORY_AREA Node
)
139 if (Node
->LeftChild
!= NULL
)
141 Node
= Node
->LeftChild
;
142 while (Node
->RightChild
!= NULL
)
143 Node
= Node
->RightChild
;
147 PMEMORY_AREA TempNode
= NULL
;
151 /* Check if we're at the end of tree. */
152 if (Node
->Parent
== NULL
)
158 while (TempNode
== Node
->LeftChild
);
163 #ifdef VALIDATE_MEMORY_AREAS
164 static VOID
MmVerifyMemoryAreas(PMADDRESS_SPACE AddressSpace
)
168 ASSERT(AddressSpace
!= NULL
);
170 /* Special case for empty tree. */
171 if (AddressSpace
->MemoryAreaRoot
== NULL
)
174 /* Traverse the tree from left to right. */
175 for (Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
177 Node
= MmIterateNextNode(Node
))
179 /* FiN: The starting address can be NULL if someone explicitely asks
180 * for NULL address. */
181 ASSERT(Node
->StartingAddress
>= AddressSpace
->LowestAddress
||
182 Node
->StartingAddress
== NULL
);
183 ASSERT(Node
->EndingAddress
>= Node
->StartingAddress
);
187 #define MmVerifyMemoryAreas(x)
191 MmDumpMemoryAreas(PMADDRESS_SPACE AddressSpace
)
195 DbgPrint("MmDumpMemoryAreas()\n");
197 /* Special case for empty tree. */
198 if (AddressSpace
->MemoryAreaRoot
== NULL
)
201 /* Traverse the tree from left to right. */
202 for (Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
204 Node
= MmIterateNextNode(Node
))
206 DbgPrint("Start %p End %p Protect %x Flags %x\n",
207 Node
->StartingAddress
, Node
->EndingAddress
,
208 Node
->Protect
, Node
->Flags
);
211 DbgPrint("Finished MmDumpMemoryAreas()\n");
215 MmLocateMemoryAreaByAddress(
216 PMADDRESS_SPACE AddressSpace
,
219 PMEMORY_AREA Node
= AddressSpace
->MemoryAreaRoot
;
221 DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
222 AddressSpace
, Address
);
224 MmVerifyMemoryAreas(AddressSpace
);
228 if (Address
< Node
->StartingAddress
)
229 Node
= Node
->LeftChild
;
230 else if (Address
>= Node
->EndingAddress
)
231 Node
= Node
->RightChild
;
234 DPRINT("MmLocateMemoryAreaByAddress(%p): %p [%p - %p]\n",
235 Address
, Node
, Node
->StartingAddress
, Node
->EndingAddress
);
240 DPRINT("MmLocateMemoryAreaByAddress(%p): 0\n", Address
);
245 MmLocateMemoryAreaByRegion(
246 PMADDRESS_SPACE AddressSpace
,
251 PVOID Extent
= (PVOID
)((ULONG_PTR
)Address
+ Length
);
253 MmVerifyMemoryAreas(AddressSpace
);
255 /* Special case for empty tree. */
256 if (AddressSpace
->MemoryAreaRoot
== NULL
)
259 /* Traverse the tree from left to right. */
260 for (Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
262 Node
= MmIterateNextNode(Node
))
264 if (Node
->StartingAddress
>= Address
&&
265 Node
->StartingAddress
< Extent
)
267 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
268 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
269 Node
->EndingAddress
);
272 if (Node
->EndingAddress
> Address
&&
273 Node
->EndingAddress
< Extent
)
275 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
276 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
277 Node
->EndingAddress
);
280 if (Node
->StartingAddress
<= Address
&&
281 Node
->EndingAddress
>= Extent
)
283 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
284 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
285 Node
->EndingAddress
);
288 if (Node
->StartingAddress
>= Extent
)
290 DPRINT("Finished MmLocateMemoryAreaByRegion() = NULL\n");
299 * @name MmCompressHelper
301 * This is helper of MmRebalanceTree. Performs a compression transformation
302 * count times, starting at root.
307 PMADDRESS_SPACE AddressSpace
,
310 PMEMORY_AREA Root
= NULL
;
311 PMEMORY_AREA Red
= AddressSpace
->MemoryAreaRoot
;
312 PMEMORY_AREA Black
= Red
->LeftChild
;
317 Root
->LeftChild
= Black
;
319 AddressSpace
->MemoryAreaRoot
= Black
;
320 Black
->Parent
= Root
;
321 Red
->LeftChild
= Black
->RightChild
;
322 if (Black
->RightChild
)
323 Black
->RightChild
->Parent
= Red
;
324 Black
->RightChild
= Red
;
330 Red
= Root
->LeftChild
;
331 Black
= Red
->LeftChild
;
337 * @name MmRebalanceTree
339 * Rebalance a memory area tree using the Tree->Vine->Balanced Tree
340 * method described in libavl documentation in chapter 4.12.
341 * (http://www.stanford.edu/~blp/avl/libavl.html/)
346 PMADDRESS_SPACE AddressSpace
)
348 PMEMORY_AREA PreviousNode
;
349 PMEMORY_AREA CurrentNode
;
350 PMEMORY_AREA TempNode
;
352 ULONG Vine
; /* Number of nodes in main vine. */
353 ULONG Leaves
; /* Nodes in incomplete bottom level, if any. */
354 INT Height
; /* Height of produced balanced tree. */
356 /* Transform the tree into Vine. */
359 CurrentNode
= AddressSpace
->MemoryAreaRoot
;
360 while (CurrentNode
!= NULL
)
362 if (CurrentNode
->RightChild
== NULL
)
364 PreviousNode
= CurrentNode
;
365 CurrentNode
= CurrentNode
->LeftChild
;
370 TempNode
= CurrentNode
->RightChild
;
372 CurrentNode
->RightChild
= TempNode
->LeftChild
;
373 if (TempNode
->LeftChild
)
374 TempNode
->LeftChild
->Parent
= CurrentNode
;
376 TempNode
->LeftChild
= CurrentNode
;
377 CurrentNode
->Parent
= TempNode
;
379 CurrentNode
= TempNode
;
381 if (PreviousNode
!= NULL
)
382 PreviousNode
->LeftChild
= TempNode
;
384 AddressSpace
->MemoryAreaRoot
= TempNode
;
385 TempNode
->Parent
= PreviousNode
;
389 /* Transform Vine back into a balanced tree. */
391 Leaves
= NodeCount
+ 1;
394 ULONG Next
= Leaves
& (Leaves
- 1);
399 Leaves
= NodeCount
+ 1 - Leaves
;
401 MmCompressHelper(AddressSpace
, Leaves
);
403 Vine
= NodeCount
- Leaves
;
404 Height
= 1 + (Leaves
> 0);
407 MmCompressHelper(AddressSpace
, Vine
/ 2);
415 PMADDRESS_SPACE AddressSpace
,
419 PMEMORY_AREA PreviousNode
;
422 MmVerifyMemoryAreas(AddressSpace
);
424 if (AddressSpace
->MemoryAreaRoot
== NULL
)
426 AddressSpace
->MemoryAreaRoot
= marea
;
427 marea
->LeftChild
= marea
->RightChild
= marea
->Parent
= NULL
;
431 Node
= AddressSpace
->MemoryAreaRoot
;
434 DPRINT("marea->EndingAddress: %p Node->StartingAddress: %p\n",
435 marea
->EndingAddress
, Node
->StartingAddress
);
436 DPRINT("marea->StartingAddress: %p Node->EndingAddress: %p\n",
437 marea
->StartingAddress
, Node
->EndingAddress
);
438 ASSERT(marea
->EndingAddress
<= Node
->StartingAddress
||
439 marea
->StartingAddress
>= Node
->EndingAddress
);
440 ASSERT(marea
->StartingAddress
!= Node
->StartingAddress
);
444 if (marea
->StartingAddress
< Node
->StartingAddress
)
445 Node
= Node
->LeftChild
;
447 Node
= Node
->RightChild
;
454 MmRebalanceTree(AddressSpace
);
455 PreviousNode
= Node
->Parent
;
459 while (Node
!= NULL
);
461 marea
->LeftChild
= marea
->RightChild
= NULL
;
462 marea
->Parent
= PreviousNode
;
463 if (marea
->StartingAddress
< PreviousNode
->StartingAddress
)
464 PreviousNode
->LeftChild
= marea
;
466 PreviousNode
->RightChild
= marea
;
471 PMADDRESS_SPACE AddressSpace
,
473 ULONG_PTR Granularity
)
475 PVOID HighestAddress
= AddressSpace
->LowestAddress
< MmSystemRangeStart
?
476 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
477 PVOID AlignedAddress
;
479 PMEMORY_AREA FirstNode
;
480 PMEMORY_AREA PreviousNode
;
482 MmVerifyMemoryAreas(AddressSpace
);
484 DPRINT("LowestAddress: %p HighestAddress: %p\n",
485 AddressSpace
->LowestAddress
, HighestAddress
);
487 AlignedAddress
= MM_ROUND_UP(AddressSpace
->LowestAddress
, Granularity
);
489 /* Special case for empty tree. */
490 if (AddressSpace
->MemoryAreaRoot
== NULL
)
492 if ((ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
494 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
495 return AlignedAddress
;
497 DPRINT("MmFindGapBottomUp: 0\n");
501 /* Go to the node with lowest address in the tree. */
502 FirstNode
= Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
504 /* Traverse the tree from left to right. */
508 Node
= MmIterateNextNode(Node
);
512 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
513 if (Node
->StartingAddress
> AlignedAddress
&&
514 (ULONG_PTR
)Node
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
516 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
517 return AlignedAddress
;
523 /* Check if there is enough space after the last memory area. */
524 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
525 if ((ULONG_PTR
)HighestAddress
> (ULONG_PTR
)AlignedAddress
&&
526 (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
528 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
529 return AlignedAddress
;
532 /* Check if there is enough space before the first memory area. */
533 AlignedAddress
= MM_ROUND_UP(AddressSpace
->LowestAddress
, Granularity
);
534 if (FirstNode
->StartingAddress
> AlignedAddress
&&
535 (ULONG_PTR
)FirstNode
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
537 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
538 return AlignedAddress
;
541 DPRINT("MmFindGapBottomUp: 0\n");
548 PMADDRESS_SPACE AddressSpace
,
550 ULONG_PTR Granularity
)
552 PVOID HighestAddress
= AddressSpace
->LowestAddress
< MmSystemRangeStart
?
553 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
554 PVOID AlignedAddress
;
556 PMEMORY_AREA PreviousNode
;
558 MmVerifyMemoryAreas(AddressSpace
);
560 DPRINT("LowestAddress: %p HighestAddress: %p\n",
561 AddressSpace
->LowestAddress
, HighestAddress
);
563 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)HighestAddress
- Length
+ 1, Granularity
);
565 /* Check for overflow. */
566 if (AlignedAddress
> HighestAddress
)
569 /* Special case for empty tree. */
570 if (AddressSpace
->MemoryAreaRoot
== NULL
)
572 if (AlignedAddress
>= (PVOID
)AddressSpace
->LowestAddress
)
574 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
575 return AlignedAddress
;
577 DPRINT("MmFindGapTopDown: 0\n");
581 /* Go to the node with highest address in the tree. */
582 Node
= MmIterateLastNode(AddressSpace
->MemoryAreaRoot
);
584 /* Check if there is enough space after the last memory area. */
585 if (Node
->EndingAddress
<= AlignedAddress
)
587 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
588 return AlignedAddress
;
591 /* Traverse the tree from left to right. */
595 Node
= MmIteratePrevNode(Node
);
599 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
601 /* Check for overflow. */
602 if (AlignedAddress
> PreviousNode
->StartingAddress
)
605 if (Node
->EndingAddress
<= AlignedAddress
)
607 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
608 return AlignedAddress
;
614 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
616 /* Check for overflow. */
617 if (AlignedAddress
> PreviousNode
->StartingAddress
)
620 if (AlignedAddress
>= (PVOID
)AddressSpace
->LowestAddress
)
622 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
623 return AlignedAddress
;
626 DPRINT("MmFindGapTopDown: 0\n");
633 PMADDRESS_SPACE AddressSpace
,
635 ULONG_PTR Granularity
,
639 return MmFindGapTopDown(AddressSpace
, Length
, Granularity
);
641 return MmFindGapBottomUp(AddressSpace
, Length
, Granularity
);
646 PMADDRESS_SPACE AddressSpace
,
649 PMEMORY_AREA Node
= AddressSpace
->MemoryAreaRoot
;
650 PMEMORY_AREA RightNeighbour
= NULL
;
651 PVOID HighestAddress
= AddressSpace
->LowestAddress
< MmSystemRangeStart
?
652 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
654 MmVerifyMemoryAreas(AddressSpace
);
656 Address
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
658 if (AddressSpace
->LowestAddress
< MmSystemRangeStart
)
660 if (Address
>= MmSystemRangeStart
)
667 if (Address
< AddressSpace
->LowestAddress
)
675 if (Address
< Node
->StartingAddress
)
677 RightNeighbour
= Node
;
678 Node
= Node
->LeftChild
;
680 else if (Address
>= Node
->EndingAddress
)
682 Node
= Node
->RightChild
;
686 DPRINT("MmFindGapAtAddress: 0\n");
693 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
694 (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
);
695 return (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
;
699 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
700 (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
);
701 return (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
;
706 * @name MmInitMemoryAreas
708 * Initialize the memory area list implementation.
714 MmInitMemoryAreas(VOID
)
716 DPRINT("MmInitMemoryAreas()\n",0);
717 return(STATUS_SUCCESS
);
722 * @name MmFreeMemoryArea
724 * Free an existing memory area.
726 * @param AddressSpace
727 * Address space to free the area from.
729 * Memory area we're about to free.
731 * Callback function for each freed page.
732 * @param FreePageContext
733 * Context passed to the callback function.
737 * @remarks Lock the address space before calling this function.
742 PMADDRESS_SPACE AddressSpace
,
743 PMEMORY_AREA MemoryArea
,
744 PMM_FREE_PAGE_FUNC FreePage
,
745 PVOID FreePageContext
)
747 PMEMORY_AREA
*ParentReplace
;
750 PROS_EPROCESS CurrentProcess
= (PROS_EPROCESS
)PsGetCurrentProcess();
752 if (AddressSpace
->Process
!= NULL
&&
753 AddressSpace
->Process
!= CurrentProcess
)
755 KeAttachProcess(&AddressSpace
->Process
->Pcb
);
758 EndAddress
= MM_ROUND_UP(MemoryArea
->EndingAddress
, PAGE_SIZE
);
759 for (Address
= (ULONG_PTR
)MemoryArea
->StartingAddress
;
760 Address
< (ULONG_PTR
)EndAddress
;
761 Address
+= PAGE_SIZE
)
763 if (MemoryArea
->Type
== MEMORY_AREA_IO_MAPPING
)
765 MmRawDeleteVirtualMapping((PVOID
)Address
);
769 BOOLEAN Dirty
= FALSE
;
770 SWAPENTRY SwapEntry
= 0;
773 if (MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)Address
))
775 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)Address
, &SwapEntry
);
779 MmDeleteVirtualMapping(AddressSpace
->Process
, (PVOID
)Address
, FALSE
, &Dirty
, &Page
);
781 if (FreePage
!= NULL
)
783 FreePage(FreePageContext
, MemoryArea
, (PVOID
)Address
,
784 Page
, SwapEntry
, (BOOLEAN
)Dirty
);
789 if (AddressSpace
->Process
!= NULL
&&
790 AddressSpace
->Process
!= CurrentProcess
)
795 /* Remove the tree item. */
797 if (MemoryArea
->Parent
!= NULL
)
799 if (MemoryArea
->Parent
->LeftChild
== MemoryArea
)
800 ParentReplace
= &MemoryArea
->Parent
->LeftChild
;
802 ParentReplace
= &MemoryArea
->Parent
->RightChild
;
805 ParentReplace
= &AddressSpace
->MemoryAreaRoot
;
807 if (MemoryArea
->RightChild
== NULL
)
809 *ParentReplace
= MemoryArea
->LeftChild
;
810 if (MemoryArea
->LeftChild
)
811 MemoryArea
->LeftChild
->Parent
= MemoryArea
->Parent
;
815 if (MemoryArea
->RightChild
->LeftChild
== NULL
)
817 MemoryArea
->RightChild
->LeftChild
= MemoryArea
->LeftChild
;
818 if (MemoryArea
->LeftChild
)
819 MemoryArea
->LeftChild
->Parent
= MemoryArea
->RightChild
;
821 *ParentReplace
= MemoryArea
->RightChild
;
822 MemoryArea
->RightChild
->Parent
= MemoryArea
->Parent
;
826 PMEMORY_AREA LowestNode
;
828 LowestNode
= MemoryArea
->RightChild
->LeftChild
;
829 while (LowestNode
->LeftChild
!= NULL
)
830 LowestNode
= LowestNode
->LeftChild
;
832 LowestNode
->Parent
->LeftChild
= LowestNode
->RightChild
;
833 if (LowestNode
->RightChild
)
834 LowestNode
->RightChild
->Parent
= LowestNode
->Parent
;
836 LowestNode
->LeftChild
= MemoryArea
->LeftChild
;
837 if (MemoryArea
->LeftChild
)
838 MemoryArea
->LeftChild
->Parent
= LowestNode
;
840 LowestNode
->RightChild
= MemoryArea
->RightChild
;
841 MemoryArea
->RightChild
->Parent
= LowestNode
;
843 *ParentReplace
= LowestNode
;
844 LowestNode
->Parent
= MemoryArea
->Parent
;
849 ExFreePoolWithTag(MemoryArea
, TAG_MAREA
);
851 DPRINT("MmFreeMemoryAreaByNode() succeeded\n");
853 return STATUS_SUCCESS
;
857 * @name MmFreeMemoryAreaByPtr
859 * Free an existing memory area given a pointer inside it.
861 * @param AddressSpace
862 * Address space to free the area from.
864 * Address in the memory area we're about to free.
866 * Callback function for each freed page.
867 * @param FreePageContext
868 * Context passed to the callback function.
872 * @see MmFreeMemoryArea
874 * @todo Should we require the BaseAddress to be really the starting
875 * address of the memory area or is the current relaxed check
876 * (BaseAddress can point anywhere in the memory area) acceptable?
878 * @remarks Lock the address space before calling this function.
882 MmFreeMemoryAreaByPtr(
883 PMADDRESS_SPACE AddressSpace
,
885 PMM_FREE_PAGE_FUNC FreePage
,
886 PVOID FreePageContext
)
888 PMEMORY_AREA MemoryArea
;
890 DPRINT("MmFreeMemoryArea(AddressSpace %p, BaseAddress %p, "
891 "FreePageContext %p)\n", AddressSpace
, BaseAddress
,
894 MmVerifyMemoryAreas(AddressSpace
);
896 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
898 if (MemoryArea
== NULL
)
901 return(STATUS_UNSUCCESSFUL
);
904 return MmFreeMemoryArea(AddressSpace
, MemoryArea
, FreePage
, FreePageContext
);
908 * @name MmCreateMemoryArea
910 * Create a memory area.
912 * @param AddressSpace
913 * Address space to create the area in.
915 * Type of the memory area.
917 * Base address for the memory area we're about the create. On
918 * input it contains either 0 (auto-assign address) or preferred
919 * address. On output it contains the starting address of the
920 * newly created area.
922 * Length of the area to allocate.
924 * Protection attributes for the memory area.
926 * Receives a pointer to the memory area on successful exit.
930 * @remarks Lock the address space before calling this function.
934 MmCreateMemoryArea(PMADDRESS_SPACE AddressSpace
,
939 PMEMORY_AREA
*Result
,
940 BOOLEAN FixedAddress
,
941 ULONG AllocationFlags
,
942 PHYSICAL_ADDRESS BoundaryAddressMultiple
)
947 PMEMORY_AREA MemoryArea
;
949 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
950 "*BaseAddress %p, Length %p, Attributes %x, TopDown: %x, "
951 "FixedAddress %x, Result %p)\n",
952 Type
, BaseAddress
, *BaseAddress
, Length
, Attributes
, TopDown
,
953 FixedAddress
, Result
);
955 MmVerifyMemoryAreas(AddressSpace
);
957 Granularity
= (MEMORY_AREA_VIRTUAL_MEMORY
== Type
? MM_VIRTMEM_GRANULARITY
: PAGE_SIZE
);
958 if ((*BaseAddress
) == 0 && !FixedAddress
)
960 tmpLength
= PAGE_ROUND_UP(Length
);
961 *BaseAddress
= MmFindGap(AddressSpace
,
964 (AllocationFlags
& MEM_TOP_DOWN
) == MEM_TOP_DOWN
);
965 if ((*BaseAddress
) == 0)
967 DPRINT("No suitable gap\n");
968 return STATUS_NO_MEMORY
;
973 tmpLength
= Length
+ ((ULONG_PTR
) *BaseAddress
974 - (ULONG_PTR
) MM_ROUND_DOWN(*BaseAddress
, Granularity
));
975 *BaseAddress
= MM_ROUND_DOWN(*BaseAddress
, Granularity
);
977 if (AddressSpace
->LowestAddress
== MmSystemRangeStart
&&
978 *BaseAddress
< MmSystemRangeStart
)
981 return STATUS_ACCESS_VIOLATION
;
984 if (AddressSpace
->LowestAddress
< MmSystemRangeStart
&&
985 (ULONG_PTR
)(*BaseAddress
) + tmpLength
> (ULONG_PTR
)MmSystemRangeStart
)
988 return STATUS_ACCESS_VIOLATION
;
991 if (BoundaryAddressMultiple
.QuadPart
!= 0)
993 EndAddress
= ((char*)(*BaseAddress
)) + tmpLength
-1;
994 ASSERT(((ULONG_PTR
)*BaseAddress
/BoundaryAddressMultiple
.QuadPart
) == ((DWORD_PTR
)EndAddress
/BoundaryAddressMultiple
.QuadPart
));
997 if (MmLocateMemoryAreaByRegion(AddressSpace
,
1001 DPRINT("Memory area already occupied\n");
1002 return STATUS_CONFLICTING_ADDRESSES
;
1006 MemoryArea
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MEMORY_AREA
),
1008 RtlZeroMemory(MemoryArea
, sizeof(MEMORY_AREA
));
1009 MemoryArea
->Type
= Type
;
1010 MemoryArea
->StartingAddress
= *BaseAddress
;
1011 MemoryArea
->EndingAddress
= (PVOID
)((ULONG_PTR
)*BaseAddress
+ tmpLength
);
1012 MemoryArea
->Protect
= Protect
;
1013 MemoryArea
->Flags
= AllocationFlags
;
1014 MemoryArea
->LockCount
= 0;
1015 MemoryArea
->PageOpCount
= 0;
1016 MemoryArea
->DeleteInProgress
= FALSE
;
1018 MmInsertMemoryArea(AddressSpace
, MemoryArea
);
1020 *Result
= MemoryArea
;
1022 DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress
);
1023 return STATUS_SUCCESS
;
1028 MmReleaseMemoryAreaIfDecommitted(PROS_EPROCESS Process
,
1029 PMADDRESS_SPACE AddressSpace
,
1032 PMEMORY_AREA MemoryArea
;
1037 MmVerifyMemoryAreas(AddressSpace
);
1039 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1040 if (MemoryArea
!= NULL
)
1042 Entry
= MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
.Flink
;
1044 while (Reserved
&& Entry
!= &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
)
1046 Region
= CONTAINING_RECORD(Entry
, MM_REGION
, RegionListEntry
);
1047 Reserved
= (MEM_RESERVE
== Region
->Type
);
1048 Entry
= Entry
->Flink
;
1053 MmFreeVirtualMemory(Process
, MemoryArea
);