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 MmIterateFirstNode
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 MmIterateNextNode
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 Attributes %x\n",
204 Node
->StartingAddress
, Node
->EndingAddress
,
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.
708 NTSTATUS INIT_FUNCTION
709 MmInitMemoryAreas(VOID
)
711 DPRINT("MmInitMemoryAreas()\n",0);
712 return(STATUS_SUCCESS
);
717 * @name MmFreeMemoryArea
719 * Free an existing memory area.
721 * @param AddressSpace
722 * Address space to free the area from.
724 * Memory area we're about to free.
726 * Callback function for each freed page.
727 * @param FreePageContext
728 * Context passed to the callback function.
732 * @remarks Lock the address space before calling this function.
737 PMADDRESS_SPACE AddressSpace
,
738 PMEMORY_AREA MemoryArea
,
739 PMM_FREE_PAGE_FUNC FreePage
,
740 PVOID FreePageContext
)
742 PMEMORY_AREA
*ParentReplace
;
745 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
747 if (AddressSpace
->Process
!= NULL
&&
748 AddressSpace
->Process
!= CurrentProcess
)
750 KeAttachProcess(&AddressSpace
->Process
->Pcb
);
753 EndAddress
= MM_ROUND_UP(MemoryArea
->EndingAddress
, PAGE_SIZE
);
754 for (Address
= (ULONG_PTR
)MemoryArea
->StartingAddress
;
755 Address
< (ULONG_PTR
)EndAddress
;
756 Address
+= PAGE_SIZE
)
758 if (MemoryArea
->Type
== MEMORY_AREA_IO_MAPPING
)
760 MmRawDeleteVirtualMapping((PVOID
)Address
);
765 SWAPENTRY SwapEntry
= 0;
768 if (MmIsPageSwapEntry(AddressSpace
->Process
, (PVOID
)Address
))
770 MmDeletePageFileMapping(AddressSpace
->Process
, (PVOID
)Address
, &SwapEntry
);
774 MmDeleteVirtualMapping(AddressSpace
->Process
, (PVOID
)Address
, FALSE
, &Dirty
, &Page
);
776 if (FreePage
!= NULL
)
778 FreePage(FreePageContext
, MemoryArea
, (PVOID
)Address
,
779 Page
, SwapEntry
, (BOOLEAN
)Dirty
);
784 if (AddressSpace
->Process
!= NULL
&&
785 AddressSpace
->Process
!= CurrentProcess
)
790 /* Remove the tree item. */
792 if (MemoryArea
->Parent
!= NULL
)
794 if (MemoryArea
->Parent
->LeftChild
== MemoryArea
)
795 ParentReplace
= &MemoryArea
->Parent
->LeftChild
;
797 ParentReplace
= &MemoryArea
->Parent
->RightChild
;
800 ParentReplace
= &AddressSpace
->MemoryAreaRoot
;
802 if (MemoryArea
->RightChild
== NULL
)
804 *ParentReplace
= MemoryArea
->LeftChild
;
805 if (MemoryArea
->LeftChild
)
806 MemoryArea
->LeftChild
->Parent
= MemoryArea
->Parent
;
810 if (MemoryArea
->RightChild
->LeftChild
== NULL
)
812 MemoryArea
->RightChild
->LeftChild
= MemoryArea
->LeftChild
;
813 if (MemoryArea
->LeftChild
)
814 MemoryArea
->LeftChild
->Parent
= MemoryArea
->RightChild
;
816 *ParentReplace
= MemoryArea
->RightChild
;
817 MemoryArea
->RightChild
->Parent
= MemoryArea
->Parent
;
821 PMEMORY_AREA LowestNode
;
823 LowestNode
= MemoryArea
->RightChild
->LeftChild
;
824 while (LowestNode
->LeftChild
!= NULL
)
825 LowestNode
= LowestNode
->LeftChild
;
827 LowestNode
->Parent
->LeftChild
= LowestNode
->RightChild
;
828 if (LowestNode
->RightChild
)
829 LowestNode
->RightChild
->Parent
= LowestNode
->Parent
;
831 LowestNode
->LeftChild
= MemoryArea
->LeftChild
;
832 if (MemoryArea
->LeftChild
)
833 MemoryArea
->LeftChild
->Parent
= LowestNode
;
835 LowestNode
->RightChild
= MemoryArea
->RightChild
;
836 MemoryArea
->RightChild
->Parent
= LowestNode
;
838 *ParentReplace
= LowestNode
;
839 LowestNode
->Parent
= MemoryArea
->Parent
;
844 ExFreePoolWithTag(MemoryArea
, TAG_MAREA
);
846 DPRINT("MmFreeMemoryAreaByNode() succeeded\n");
848 return STATUS_SUCCESS
;
852 * @name MmFreeMemoryAreaByPtr
854 * Free an existing memory area given a pointer inside it.
856 * @param AddressSpace
857 * Address space to free the area from.
859 * Address in the memory area we're about to free.
861 * Callback function for each freed page.
862 * @param FreePageContext
863 * Context passed to the callback function.
867 * @see MmFreeMemoryArea
869 * @todo Should we require the BaseAddress to be really the starting
870 * address of the memory area or is the current relaxed check
871 * (BaseAddress can point anywhere in the memory area) acceptable?
873 * @remarks Lock the address space before calling this function.
877 MmFreeMemoryAreaByPtr(
878 PMADDRESS_SPACE AddressSpace
,
880 PMM_FREE_PAGE_FUNC FreePage
,
881 PVOID FreePageContext
)
883 PMEMORY_AREA MemoryArea
;
885 DPRINT("MmFreeMemoryArea(AddressSpace %p, BaseAddress %p, "
886 "FreePageContext %p)\n", AddressSpace
, BaseAddress
,
889 MmVerifyMemoryAreas(AddressSpace
);
891 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
893 if (MemoryArea
== NULL
)
896 return(STATUS_UNSUCCESSFUL
);
899 return MmFreeMemoryArea(AddressSpace
, MemoryArea
, FreePage
, FreePageContext
);
903 * @name MmCreateMemoryArea
905 * Create a memory area.
907 * @param AddressSpace
908 * Address space to create the area in.
910 * Type of the memory area.
912 * Base address for the memory area we're about the create. On
913 * input it contains either 0 (auto-assign address) or preferred
914 * address. On output it contains the starting address of the
915 * newly created area.
917 * Length of the area to allocate.
919 * Protection attributes for the memory area.
921 * Receives a pointer to the memory area on successful exit.
925 * @remarks Lock the address space before calling this function.
929 MmCreateMemoryArea(PEPROCESS Process
,
930 PMADDRESS_SPACE AddressSpace
,
935 PMEMORY_AREA
*Result
,
936 BOOLEAN FixedAddress
,
938 PHYSICAL_ADDRESS BoundaryAddressMultiple
)
943 PMEMORY_AREA MemoryArea
;
945 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
946 "*BaseAddress %p, Length %p, Attributes %x, TopDown: %x, "
947 "FixedAddress %x, Result %p)\n",
948 Type
, BaseAddress
, *BaseAddress
, Length
, Attributes
, TopDown
,
949 FixedAddress
, Result
);
951 MmVerifyMemoryAreas(AddressSpace
);
953 Granularity
= (MEMORY_AREA_VIRTUAL_MEMORY
== Type
? MM_VIRTMEM_GRANULARITY
: PAGE_SIZE
);
954 if ((*BaseAddress
) == 0 && !FixedAddress
)
956 tmpLength
= PAGE_ROUND_UP(Length
);
957 *BaseAddress
= MmFindGap(AddressSpace
,
961 if ((*BaseAddress
) == 0)
963 DPRINT("No suitable gap\n");
964 return STATUS_NO_MEMORY
;
969 tmpLength
= Length
+ ((ULONG_PTR
) *BaseAddress
970 - (ULONG_PTR
) MM_ROUND_DOWN(*BaseAddress
, Granularity
));
971 *BaseAddress
= MM_ROUND_DOWN(*BaseAddress
, Granularity
);
973 if (AddressSpace
->LowestAddress
== MmSystemRangeStart
&&
974 *BaseAddress
< MmSystemRangeStart
)
977 return STATUS_ACCESS_VIOLATION
;
980 if (AddressSpace
->LowestAddress
< MmSystemRangeStart
&&
981 (ULONG_PTR
)(*BaseAddress
) + tmpLength
> (ULONG_PTR
)MmSystemRangeStart
)
984 return STATUS_ACCESS_VIOLATION
;
987 if (BoundaryAddressMultiple
.QuadPart
!= 0)
989 EndAddress
= ((char*)(*BaseAddress
)) + tmpLength
-1;
990 ASSERT(((ULONG_PTR
)*BaseAddress
/BoundaryAddressMultiple
.QuadPart
) == ((DWORD_PTR
)EndAddress
/BoundaryAddressMultiple
.QuadPart
));
993 if (MmLocateMemoryAreaByRegion(AddressSpace
,
997 DPRINT("Memory area already occupied\n");
998 return STATUS_CONFLICTING_ADDRESSES
;
1002 MemoryArea
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MEMORY_AREA
),
1004 RtlZeroMemory(MemoryArea
, sizeof(MEMORY_AREA
));
1005 MemoryArea
->Type
= Type
;
1006 MemoryArea
->StartingAddress
= *BaseAddress
;
1007 MemoryArea
->EndingAddress
= (PVOID
)((ULONG_PTR
)*BaseAddress
+ tmpLength
);
1008 MemoryArea
->Attributes
= Attributes
;
1009 MemoryArea
->LockCount
= 0;
1010 MemoryArea
->PageOpCount
= 0;
1011 MemoryArea
->DeleteInProgress
= FALSE
;
1013 MmInsertMemoryArea(AddressSpace
, MemoryArea
);
1015 *Result
= MemoryArea
;
1017 DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress
);
1018 return STATUS_SUCCESS
;
1023 MmReleaseMemoryAreaIfDecommitted(PEPROCESS Process
,
1024 PMADDRESS_SPACE AddressSpace
,
1027 PMEMORY_AREA MemoryArea
;
1032 MmVerifyMemoryAreas(AddressSpace
);
1034 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1035 if (MemoryArea
!= NULL
)
1037 Entry
= MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
.Flink
;
1039 while (Reserved
&& Entry
!= &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
)
1041 Region
= CONTAINING_RECORD(Entry
, MM_REGION
, RegionListEntry
);
1042 Reserved
= (MEM_RESERVE
== Region
->Type
);
1043 Entry
= Entry
->Flink
;
1048 MmFreeVirtualMemory(Process
, MemoryArea
);