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
35 * Thomas Weidenmueller
36 * Gunnar Andre' Dalsnes
44 /* INCLUDES *****************************************************************/
48 #include <internal/debug.h>
50 /* #define VALIDATE_MEMORY_AREAS */
52 /* FUNCTIONS *****************************************************************/
55 * @name MmIterateFirstNode
58 * Head node of the MEMORY_AREA tree.
60 * @return The leftmost MEMORY_AREA node (ie. the one with lowest
64 static PMEMORY_AREA
MmIterateFirstNode(PMEMORY_AREA Node
)
66 while (Node
->LeftChild
!= NULL
)
67 Node
= Node
->LeftChild
;
73 * @name MmIterateNextNode
76 * Current node in the tree.
78 * @return Next node in the tree (sorted by address).
81 static PMEMORY_AREA
MmIterateNextNode(PMEMORY_AREA Node
)
83 if (Node
->RightChild
!= NULL
)
85 Node
= Node
->RightChild
;
86 while (Node
->LeftChild
!= NULL
)
87 Node
= Node
->LeftChild
;
91 PMEMORY_AREA TempNode
= NULL
;
95 /* Check if we're at the end of tree. */
96 if (Node
->Parent
== NULL
)
102 while (TempNode
== Node
->RightChild
);
108 * @name MmIterateLastNode
111 * Head node of the MEMORY_AREA tree.
113 * @return The rightmost MEMORY_AREA node (ie. the one with highest
117 static PMEMORY_AREA
MmIterateLastNode(PMEMORY_AREA Node
)
119 while (Node
->RightChild
!= NULL
)
120 Node
= Node
->RightChild
;
126 * @name MmIteratePreviousNode
129 * Current node in the tree.
131 * @return Previous node in the tree (sorted by address).
134 static PMEMORY_AREA
MmIteratePrevNode(PMEMORY_AREA Node
)
136 if (Node
->LeftChild
!= NULL
)
138 Node
= Node
->LeftChild
;
139 while (Node
->RightChild
!= NULL
)
140 Node
= Node
->RightChild
;
144 PMEMORY_AREA TempNode
= NULL
;
148 /* Check if we're at the end of tree. */
149 if (Node
->Parent
== NULL
)
155 while (TempNode
== Node
->LeftChild
);
160 #ifdef VALIDATE_MEMORY_AREAS
161 static VOID
MmVerifyMemoryAreas(PMADDRESS_SPACE AddressSpace
)
165 ASSERT(AddressSpace
!= NULL
);
167 /* Special case for empty tree. */
168 if (AddressSpace
->MemoryAreaRoot
== NULL
)
171 /* Traverse the tree from left to right. */
172 for (Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
174 Node
= MmIterateNextNode(Node
))
176 /* FiN: The starting address can be NULL if someone explicitely asks
177 * for NULL address. */
178 ASSERT(Node
->StartingAddress
>= AddressSpace
->LowestAddress
||
179 Node
->StartingAddress
== NULL
);
180 ASSERT(Node
->EndingAddress
>= Node
->StartingAddress
);
184 #define MmVerifyMemoryAreas(x)
188 MmDumpMemoryAreas(PMADDRESS_SPACE AddressSpace
)
192 DbgPrint("MmDumpMemoryAreas()\n");
194 /* Special case for empty tree. */
195 if (AddressSpace
->MemoryAreaRoot
== NULL
)
198 /* Traverse the tree from left to right. */
199 for (Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
201 Node
= MmIterateNextNode(Node
))
203 DbgPrint("Start %p End %p Protect %x Flags %x\n",
204 Node
->StartingAddress
, Node
->EndingAddress
,
205 Node
->Protect
, Node
->Flags
);
208 DbgPrint("Finished MmDumpMemoryAreas()\n");
212 MmLocateMemoryAreaByAddress(
213 PMADDRESS_SPACE AddressSpace
,
216 PMEMORY_AREA Node
= AddressSpace
->MemoryAreaRoot
;
218 DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
219 AddressSpace
, Address
);
221 MmVerifyMemoryAreas(AddressSpace
);
225 if (Address
< Node
->StartingAddress
)
226 Node
= Node
->LeftChild
;
227 else if (Address
>= Node
->EndingAddress
)
228 Node
= Node
->RightChild
;
231 DPRINT("MmLocateMemoryAreaByAddress(%p): %p [%p - %p]\n",
232 Address
, Node
, Node
->StartingAddress
, Node
->EndingAddress
);
237 DPRINT("MmLocateMemoryAreaByAddress(%p): 0\n", Address
);
242 MmLocateMemoryAreaByRegion(
243 PMADDRESS_SPACE AddressSpace
,
248 PVOID Extent
= (PVOID
)((ULONG_PTR
)Address
+ Length
);
250 MmVerifyMemoryAreas(AddressSpace
);
252 /* Special case for empty tree. */
253 if (AddressSpace
->MemoryAreaRoot
== NULL
)
256 /* Traverse the tree from left to right. */
257 for (Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
259 Node
= MmIterateNextNode(Node
))
261 if (Node
->StartingAddress
>= Address
&&
262 Node
->StartingAddress
< Extent
)
264 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
265 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
266 Node
->EndingAddress
);
269 if (Node
->EndingAddress
> Address
&&
270 Node
->EndingAddress
< Extent
)
272 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
273 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
274 Node
->EndingAddress
);
277 if (Node
->StartingAddress
<= Address
&&
278 Node
->EndingAddress
>= Extent
)
280 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
281 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
282 Node
->EndingAddress
);
285 if (Node
->StartingAddress
>= Extent
)
287 DPRINT("Finished MmLocateMemoryAreaByRegion() = NULL\n");
296 * @name MmCompressHelper
298 * This is helper of MmRebalanceTree. Performs a compression transformation
299 * count times, starting at root.
304 PMADDRESS_SPACE AddressSpace
,
307 PMEMORY_AREA Root
= NULL
;
308 PMEMORY_AREA Red
= AddressSpace
->MemoryAreaRoot
;
309 PMEMORY_AREA Black
= Red
->LeftChild
;
314 Root
->LeftChild
= Black
;
316 AddressSpace
->MemoryAreaRoot
= Black
;
317 Black
->Parent
= Root
;
318 Red
->LeftChild
= Black
->RightChild
;
319 if (Black
->RightChild
)
320 Black
->RightChild
->Parent
= Red
;
321 Black
->RightChild
= Red
;
327 Red
= Root
->LeftChild
;
328 Black
= Red
->LeftChild
;
334 * @name MmRebalanceTree
336 * Rebalance a memory area tree using the Tree->Vine->Balanced Tree
337 * method described in libavl documentation in chapter 4.12.
338 * (http://www.stanford.edu/~blp/avl/libavl.html/)
343 PMADDRESS_SPACE AddressSpace
)
345 PMEMORY_AREA PreviousNode
;
346 PMEMORY_AREA CurrentNode
;
347 PMEMORY_AREA TempNode
;
349 ULONG Vine
; /* Number of nodes in main vine. */
350 ULONG Leaves
; /* Nodes in incomplete bottom level, if any. */
351 INT Height
; /* Height of produced balanced tree. */
353 /* Transform the tree into Vine. */
356 CurrentNode
= AddressSpace
->MemoryAreaRoot
;
357 while (CurrentNode
!= NULL
)
359 if (CurrentNode
->RightChild
== NULL
)
361 PreviousNode
= CurrentNode
;
362 CurrentNode
= CurrentNode
->LeftChild
;
367 TempNode
= CurrentNode
->RightChild
;
369 CurrentNode
->RightChild
= TempNode
->LeftChild
;
370 if (TempNode
->LeftChild
)
371 TempNode
->LeftChild
->Parent
= CurrentNode
;
373 TempNode
->LeftChild
= CurrentNode
;
374 CurrentNode
->Parent
= TempNode
;
376 CurrentNode
= TempNode
;
378 if (PreviousNode
!= NULL
)
379 PreviousNode
->LeftChild
= TempNode
;
381 AddressSpace
->MemoryAreaRoot
= TempNode
;
382 TempNode
->Parent
= PreviousNode
;
386 /* Transform Vine back into a balanced tree. */
388 Leaves
= NodeCount
+ 1;
391 ULONG Next
= Leaves
& (Leaves
- 1);
396 Leaves
= NodeCount
+ 1 - Leaves
;
398 MmCompressHelper(AddressSpace
, Leaves
);
400 Vine
= NodeCount
- Leaves
;
401 Height
= 1 + (Leaves
> 0);
404 MmCompressHelper(AddressSpace
, Vine
/ 2);
412 PMADDRESS_SPACE AddressSpace
,
416 PMEMORY_AREA PreviousNode
;
419 MmVerifyMemoryAreas(AddressSpace
);
421 if (AddressSpace
->MemoryAreaRoot
== NULL
)
423 AddressSpace
->MemoryAreaRoot
= marea
;
424 marea
->LeftChild
= marea
->RightChild
= marea
->Parent
= NULL
;
428 Node
= AddressSpace
->MemoryAreaRoot
;
431 DPRINT("marea->EndingAddress: %p Node->StartingAddress: %p\n",
432 marea
->EndingAddress
, Node
->StartingAddress
);
433 DPRINT("marea->StartingAddress: %p Node->EndingAddress: %p\n",
434 marea
->StartingAddress
, Node
->EndingAddress
);
435 ASSERT(marea
->EndingAddress
<= Node
->StartingAddress
||
436 marea
->StartingAddress
>= Node
->EndingAddress
);
437 ASSERT(marea
->StartingAddress
!= Node
->StartingAddress
);
441 if (marea
->StartingAddress
< Node
->StartingAddress
)
442 Node
= Node
->LeftChild
;
444 Node
= Node
->RightChild
;
451 MmRebalanceTree(AddressSpace
);
452 PreviousNode
= Node
->Parent
;
456 while (Node
!= NULL
);
458 marea
->LeftChild
= marea
->RightChild
= NULL
;
459 marea
->Parent
= PreviousNode
;
460 if (marea
->StartingAddress
< PreviousNode
->StartingAddress
)
461 PreviousNode
->LeftChild
= marea
;
463 PreviousNode
->RightChild
= marea
;
468 PMADDRESS_SPACE AddressSpace
,
470 ULONG_PTR Granularity
)
472 PVOID HighestAddress
= AddressSpace
->LowestAddress
< MmSystemRangeStart
?
473 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
474 PVOID AlignedAddress
;
476 PMEMORY_AREA FirstNode
;
477 PMEMORY_AREA PreviousNode
;
479 MmVerifyMemoryAreas(AddressSpace
);
481 DPRINT("LowestAddress: %p HighestAddress: %p\n",
482 AddressSpace
->LowestAddress
, HighestAddress
);
484 AlignedAddress
= MM_ROUND_UP(AddressSpace
->LowestAddress
, Granularity
);
486 /* Special case for empty tree. */
487 if (AddressSpace
->MemoryAreaRoot
== NULL
)
489 if ((ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
491 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
492 return AlignedAddress
;
494 DPRINT("MmFindGapBottomUp: 0\n");
498 /* Go to the node with lowest address in the tree. */
499 FirstNode
= Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
501 /* Traverse the tree from left to right. */
505 Node
= MmIterateNextNode(Node
);
509 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
510 if (Node
->StartingAddress
> AlignedAddress
&&
511 (ULONG_PTR
)Node
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
513 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
514 return AlignedAddress
;
520 /* Check if there is enough space after the last memory area. */
521 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
522 if ((ULONG_PTR
)HighestAddress
> (ULONG_PTR
)AlignedAddress
&&
523 (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
525 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
526 return AlignedAddress
;
529 /* Check if there is enough space before the first memory area. */
530 AlignedAddress
= MM_ROUND_UP(AddressSpace
->LowestAddress
, Granularity
);
531 if (FirstNode
->StartingAddress
> AlignedAddress
&&
532 (ULONG_PTR
)FirstNode
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
534 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
535 return AlignedAddress
;
538 DPRINT("MmFindGapBottomUp: 0\n");
545 PMADDRESS_SPACE AddressSpace
,
547 ULONG_PTR Granularity
)
549 PVOID HighestAddress
= AddressSpace
->LowestAddress
< MmSystemRangeStart
?
550 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
551 PVOID AlignedAddress
;
553 PMEMORY_AREA PreviousNode
;
555 MmVerifyMemoryAreas(AddressSpace
);
557 DPRINT("LowestAddress: %p HighestAddress: %p\n",
558 AddressSpace
->LowestAddress
, HighestAddress
);
560 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)HighestAddress
- Length
+ 1, Granularity
);
562 /* Check for overflow. */
563 if (AlignedAddress
> HighestAddress
)
566 /* Special case for empty tree. */
567 if (AddressSpace
->MemoryAreaRoot
== NULL
)
569 if (AlignedAddress
>= (PVOID
)AddressSpace
->LowestAddress
)
571 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
572 return AlignedAddress
;
574 DPRINT("MmFindGapTopDown: 0\n");
578 /* Go to the node with highest address in the tree. */
579 Node
= MmIterateLastNode(AddressSpace
->MemoryAreaRoot
);
581 /* Check if there is enough space after the last memory area. */
582 if (Node
->EndingAddress
<= AlignedAddress
)
584 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
585 return AlignedAddress
;
588 /* Traverse the tree from left to right. */
592 Node
= MmIteratePrevNode(Node
);
596 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
598 /* Check for overflow. */
599 if (AlignedAddress
> PreviousNode
->StartingAddress
)
602 if (Node
->EndingAddress
<= AlignedAddress
)
604 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
605 return AlignedAddress
;
611 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
613 /* Check for overflow. */
614 if (AlignedAddress
> PreviousNode
->StartingAddress
)
617 if (AlignedAddress
>= (PVOID
)AddressSpace
->LowestAddress
)
619 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
620 return AlignedAddress
;
623 DPRINT("MmFindGapTopDown: 0\n");
630 PMADDRESS_SPACE AddressSpace
,
632 ULONG_PTR Granularity
,
636 return MmFindGapTopDown(AddressSpace
, Length
, Granularity
);
638 return MmFindGapBottomUp(AddressSpace
, Length
, Granularity
);
643 PMADDRESS_SPACE AddressSpace
,
646 PMEMORY_AREA Node
= AddressSpace
->MemoryAreaRoot
;
647 PMEMORY_AREA RightNeighbour
= NULL
;
648 PVOID HighestAddress
= AddressSpace
->LowestAddress
< MmSystemRangeStart
?
649 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
651 MmVerifyMemoryAreas(AddressSpace
);
653 Address
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
655 if (AddressSpace
->LowestAddress
< MmSystemRangeStart
)
657 if (Address
>= MmSystemRangeStart
)
664 if (Address
< AddressSpace
->LowestAddress
)
672 if (Address
< Node
->StartingAddress
)
674 RightNeighbour
= Node
;
675 Node
= Node
->LeftChild
;
677 else if (Address
>= Node
->EndingAddress
)
679 Node
= Node
->RightChild
;
683 DPRINT("MmFindGapAtAddress: 0\n");
690 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
691 (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
);
692 return (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
;
696 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
697 (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
);
698 return (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
;
703 * @name MmInitMemoryAreas
705 * Initialize the memory area list implementation.
711 MmInitMemoryAreas(VOID
)
713 DPRINT("MmInitMemoryAreas()\n",0);
714 return(STATUS_SUCCESS
);
719 * @name MmFreeMemoryArea
721 * Free an existing memory area.
723 * @param AddressSpace
724 * Address space to free the area from.
726 * Memory area we're about to free.
728 * Callback function for each freed page.
729 * @param FreePageContext
730 * Context passed to the callback function.
734 * @remarks Lock the address space before calling this function.
739 PMADDRESS_SPACE AddressSpace
,
740 PMEMORY_AREA MemoryArea
,
741 PMM_FREE_PAGE_FUNC FreePage
,
742 PVOID FreePageContext
)
744 PMEMORY_AREA
*ParentReplace
;
747 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
749 if (AddressSpace
->Process
!= NULL
&&
750 AddressSpace
->Process
!= CurrentProcess
)
752 KeAttachProcess(&AddressSpace
->Process
->Pcb
);
755 EndAddress
= MM_ROUND_UP(MemoryArea
->EndingAddress
, PAGE_SIZE
);
756 for (Address
= (ULONG_PTR
)MemoryArea
->StartingAddress
;
757 Address
< (ULONG_PTR
)EndAddress
;
758 Address
+= PAGE_SIZE
)
760 if (MemoryArea
->Type
== MEMORY_AREA_IO_MAPPING
)
762 MmRawDeleteVirtualMapping((PVOID
)Address
);
767 SWAPENTRY SwapEntry
= 0;
770 if (MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)Address
))
772 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)Address
, &SwapEntry
);
776 MmDeleteVirtualMapping(AddressSpace
->Process
, (PVOID
)Address
, FALSE
, &Dirty
, &Page
);
778 if (FreePage
!= NULL
)
780 FreePage(FreePageContext
, MemoryArea
, (PVOID
)Address
,
781 Page
, SwapEntry
, (BOOLEAN
)Dirty
);
786 if (AddressSpace
->Process
!= NULL
&&
787 AddressSpace
->Process
!= CurrentProcess
)
792 /* Remove the tree item. */
794 if (MemoryArea
->Parent
!= NULL
)
796 if (MemoryArea
->Parent
->LeftChild
== MemoryArea
)
797 ParentReplace
= &MemoryArea
->Parent
->LeftChild
;
799 ParentReplace
= &MemoryArea
->Parent
->RightChild
;
802 ParentReplace
= &AddressSpace
->MemoryAreaRoot
;
804 if (MemoryArea
->RightChild
== NULL
)
806 *ParentReplace
= MemoryArea
->LeftChild
;
807 if (MemoryArea
->LeftChild
)
808 MemoryArea
->LeftChild
->Parent
= MemoryArea
->Parent
;
812 if (MemoryArea
->RightChild
->LeftChild
== NULL
)
814 MemoryArea
->RightChild
->LeftChild
= MemoryArea
->LeftChild
;
815 if (MemoryArea
->LeftChild
)
816 MemoryArea
->LeftChild
->Parent
= MemoryArea
->RightChild
;
818 *ParentReplace
= MemoryArea
->RightChild
;
819 MemoryArea
->RightChild
->Parent
= MemoryArea
->Parent
;
823 PMEMORY_AREA LowestNode
;
825 LowestNode
= MemoryArea
->RightChild
->LeftChild
;
826 while (LowestNode
->LeftChild
!= NULL
)
827 LowestNode
= LowestNode
->LeftChild
;
829 LowestNode
->Parent
->LeftChild
= LowestNode
->RightChild
;
830 if (LowestNode
->RightChild
)
831 LowestNode
->RightChild
->Parent
= LowestNode
->Parent
;
833 LowestNode
->LeftChild
= MemoryArea
->LeftChild
;
834 if (MemoryArea
->LeftChild
)
835 MemoryArea
->LeftChild
->Parent
= LowestNode
;
837 LowestNode
->RightChild
= MemoryArea
->RightChild
;
838 MemoryArea
->RightChild
->Parent
= LowestNode
;
840 *ParentReplace
= LowestNode
;
841 LowestNode
->Parent
= MemoryArea
->Parent
;
846 ExFreePoolWithTag(MemoryArea
, TAG_MAREA
);
848 DPRINT("MmFreeMemoryAreaByNode() succeeded\n");
850 return STATUS_SUCCESS
;
854 * @name MmFreeMemoryAreaByPtr
856 * Free an existing memory area given a pointer inside it.
858 * @param AddressSpace
859 * Address space to free the area from.
861 * Address in the memory area we're about to free.
863 * Callback function for each freed page.
864 * @param FreePageContext
865 * Context passed to the callback function.
869 * @see MmFreeMemoryArea
871 * @todo Should we require the BaseAddress to be really the starting
872 * address of the memory area or is the current relaxed check
873 * (BaseAddress can point anywhere in the memory area) acceptable?
875 * @remarks Lock the address space before calling this function.
879 MmFreeMemoryAreaByPtr(
880 PMADDRESS_SPACE AddressSpace
,
882 PMM_FREE_PAGE_FUNC FreePage
,
883 PVOID FreePageContext
)
885 PMEMORY_AREA MemoryArea
;
887 DPRINT("MmFreeMemoryArea(AddressSpace %p, BaseAddress %p, "
888 "FreePageContext %p)\n", AddressSpace
, BaseAddress
,
891 MmVerifyMemoryAreas(AddressSpace
);
893 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
895 if (MemoryArea
== NULL
)
898 return(STATUS_UNSUCCESSFUL
);
901 return MmFreeMemoryArea(AddressSpace
, MemoryArea
, FreePage
, FreePageContext
);
905 * @name MmCreateMemoryArea
907 * Create a memory area.
909 * @param AddressSpace
910 * Address space to create the area in.
912 * Type of the memory area.
914 * Base address for the memory area we're about the create. On
915 * input it contains either 0 (auto-assign address) or preferred
916 * address. On output it contains the starting address of the
917 * newly created area.
919 * Length of the area to allocate.
921 * Protection attributes for the memory area.
923 * Receives a pointer to the memory area on successful exit.
927 * @remarks Lock the address space before calling this function.
931 MmCreateMemoryArea(PMADDRESS_SPACE AddressSpace
,
936 PMEMORY_AREA
*Result
,
937 BOOLEAN FixedAddress
,
938 ULONG AllocationFlags
,
939 PHYSICAL_ADDRESS BoundaryAddressMultiple
)
944 PMEMORY_AREA MemoryArea
;
946 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
947 "*BaseAddress %p, Length %p, Attributes %x, TopDown: %x, "
948 "FixedAddress %x, Result %p)\n",
949 Type
, BaseAddress
, *BaseAddress
, Length
, Attributes
, TopDown
,
950 FixedAddress
, Result
);
952 MmVerifyMemoryAreas(AddressSpace
);
954 Granularity
= (MEMORY_AREA_VIRTUAL_MEMORY
== Type
? MM_VIRTMEM_GRANULARITY
: PAGE_SIZE
);
955 if ((*BaseAddress
) == 0 && !FixedAddress
)
957 tmpLength
= PAGE_ROUND_UP(Length
);
958 *BaseAddress
= MmFindGap(AddressSpace
,
961 (AllocationFlags
& MEM_TOP_DOWN
) == MEM_TOP_DOWN
);
962 if ((*BaseAddress
) == 0)
964 DPRINT("No suitable gap\n");
965 return STATUS_NO_MEMORY
;
970 tmpLength
= Length
+ ((ULONG_PTR
) *BaseAddress
971 - (ULONG_PTR
) MM_ROUND_DOWN(*BaseAddress
, Granularity
));
972 *BaseAddress
= MM_ROUND_DOWN(*BaseAddress
, Granularity
);
974 if (AddressSpace
->LowestAddress
== MmSystemRangeStart
&&
975 *BaseAddress
< MmSystemRangeStart
)
978 return STATUS_ACCESS_VIOLATION
;
981 if (AddressSpace
->LowestAddress
< MmSystemRangeStart
&&
982 (ULONG_PTR
)(*BaseAddress
) + tmpLength
> (ULONG_PTR
)MmSystemRangeStart
)
985 return STATUS_ACCESS_VIOLATION
;
988 if (BoundaryAddressMultiple
.QuadPart
!= 0)
990 EndAddress
= ((char*)(*BaseAddress
)) + tmpLength
-1;
991 ASSERT(((ULONG_PTR
)*BaseAddress
/BoundaryAddressMultiple
.QuadPart
) == ((DWORD_PTR
)EndAddress
/BoundaryAddressMultiple
.QuadPart
));
994 if (MmLocateMemoryAreaByRegion(AddressSpace
,
998 DPRINT("Memory area already occupied\n");
999 return STATUS_CONFLICTING_ADDRESSES
;
1003 MemoryArea
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MEMORY_AREA
),
1005 RtlZeroMemory(MemoryArea
, sizeof(MEMORY_AREA
));
1006 MemoryArea
->Type
= Type
;
1007 MemoryArea
->StartingAddress
= *BaseAddress
;
1008 MemoryArea
->EndingAddress
= (PVOID
)((ULONG_PTR
)*BaseAddress
+ tmpLength
);
1009 MemoryArea
->Protect
= Protect
;
1010 MemoryArea
->Flags
= AllocationFlags
;
1011 MemoryArea
->LockCount
= 0;
1012 MemoryArea
->PageOpCount
= 0;
1013 MemoryArea
->DeleteInProgress
= FALSE
;
1015 MmInsertMemoryArea(AddressSpace
, MemoryArea
);
1017 *Result
= MemoryArea
;
1019 DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress
);
1020 return STATUS_SUCCESS
;
1025 MmReleaseMemoryAreaIfDecommitted(PEPROCESS Process
,
1026 PMADDRESS_SPACE AddressSpace
,
1029 PMEMORY_AREA MemoryArea
;
1034 MmVerifyMemoryAreas(AddressSpace
);
1036 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1037 if (MemoryArea
!= NULL
)
1039 Entry
= MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
.Flink
;
1041 while (Reserved
&& Entry
!= &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
)
1043 Region
= CONTAINING_RECORD(Entry
, MM_REGION
, RegionListEntry
);
1044 Reserved
= (MEM_RESERVE
== Region
->Type
);
1045 Entry
= Entry
->Flink
;
1050 MmFreeVirtualMemory(Process
, MemoryArea
);