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 MEMORY_AREA MiStaticMemoryAreas
[MI_STATIC_MEMORY_AREAS
];
49 ULONG MiStaticMemoryAreaCount
;
51 /* #define VALIDATE_MEMORY_AREAS */
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
);
161 #ifdef VALIDATE_MEMORY_AREAS
162 static VOID
MmVerifyMemoryAreas(PMMSUPPORT AddressSpace
)
166 ASSERT(AddressSpace
!= NULL
);
168 /* Special case for empty tree. */
169 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
172 /* Traverse the tree from left to right. */
173 for (Node
= MmIterateFirstNode(AddressSpace
->WorkingSetExpansionLinks
.Flink
);
175 Node
= MmIterateNextNode(Node
))
177 /* FiN: The starting address can be NULL if someone explicitely asks
178 * for NULL address. */
179 ASSERT(Node
->StartingAddress
== NULL
);
180 ASSERT(Node
->EndingAddress
>= Node
->StartingAddress
);
184 #define MmVerifyMemoryAreas(x)
188 MmDumpMemoryAreas(PMMSUPPORT AddressSpace
)
192 DbgPrint("MmDumpMemoryAreas()\n");
194 /* Special case for empty tree. */
195 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
198 /* Traverse the tree from left to right. */
199 for (Node
= MmIterateFirstNode((PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
);
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 PMMSUPPORT AddressSpace
,
216 PMEMORY_AREA Node
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
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 PMMSUPPORT AddressSpace
,
248 PVOID Extent
= (PVOID
)((ULONG_PTR
)Address
+ Length
);
250 MmVerifyMemoryAreas(AddressSpace
);
252 /* Special case for empty tree. */
253 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
256 /* Traverse the tree from left to right. */
257 for (Node
= MmIterateFirstNode((PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
);
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 PMMSUPPORT AddressSpace
,
307 PMEMORY_AREA Root
= NULL
;
308 PMEMORY_AREA Red
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
309 PMEMORY_AREA Black
= Red
->LeftChild
;
314 Root
->LeftChild
= Black
;
316 AddressSpace
->WorkingSetExpansionLinks
.Flink
= (PVOID
)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 PMMSUPPORT 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
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
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
->WorkingSetExpansionLinks
.Flink
= (PVOID
)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 PMMSUPPORT AddressSpace
,
416 PMEMORY_AREA PreviousNode
;
419 MmVerifyMemoryAreas(AddressSpace
);
421 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
423 AddressSpace
->WorkingSetExpansionLinks
.Flink
= (PVOID
)marea
;
424 marea
->LeftChild
= marea
->RightChild
= marea
->Parent
= NULL
;
428 Node
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
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 PMMSUPPORT AddressSpace
,
470 ULONG_PTR Granularity
)
472 PVOID LowestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ? MM_LOWEST_USER_ADDRESS
: MmSystemRangeStart
;
473 PVOID HighestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ?
474 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
475 PVOID AlignedAddress
;
477 PMEMORY_AREA FirstNode
;
478 PMEMORY_AREA PreviousNode
;
480 MmVerifyMemoryAreas(AddressSpace
);
482 DPRINT("LowestAddress: %p HighestAddress: %p\n",
483 LowestAddress
, HighestAddress
);
485 AlignedAddress
= MM_ROUND_UP(LowestAddress
, Granularity
);
487 /* Special case for empty tree. */
488 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
490 if ((ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
492 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
493 return AlignedAddress
;
495 DPRINT("MmFindGapBottomUp: 0\n");
499 /* Go to the node with lowest address in the tree. */
500 FirstNode
= Node
= MmIterateFirstNode((PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
);
502 /* Traverse the tree from left to right. */
506 Node
= MmIterateNextNode(Node
);
510 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
511 if (Node
->StartingAddress
> AlignedAddress
&&
512 (ULONG_PTR
)Node
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
514 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
515 return AlignedAddress
;
521 /* Check if there is enough space after the last memory area. */
522 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
523 if ((ULONG_PTR
)HighestAddress
> (ULONG_PTR
)AlignedAddress
&&
524 (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
526 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
527 return AlignedAddress
;
530 /* Check if there is enough space before the first memory area. */
531 AlignedAddress
= MM_ROUND_UP(LowestAddress
, Granularity
);
532 if (FirstNode
->StartingAddress
> AlignedAddress
&&
533 (ULONG_PTR
)FirstNode
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
535 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
536 return AlignedAddress
;
539 DPRINT("MmFindGapBottomUp: 0\n");
546 PMMSUPPORT AddressSpace
,
548 ULONG_PTR Granularity
)
550 PVOID LowestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ? MM_LOWEST_USER_ADDRESS
: MmSystemRangeStart
;
551 PVOID HighestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ?
552 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
553 PVOID AlignedAddress
;
555 PMEMORY_AREA PreviousNode
;
557 MmVerifyMemoryAreas(AddressSpace
);
559 DPRINT("LowestAddress: %p HighestAddress: %p\n",
560 LowestAddress
, HighestAddress
);
562 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)HighestAddress
- Length
+ 1, Granularity
);
564 /* Check for overflow. */
565 if (AlignedAddress
> HighestAddress
)
568 /* Special case for empty tree. */
569 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
571 if (AlignedAddress
>= LowestAddress
)
573 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
574 return AlignedAddress
;
576 DPRINT("MmFindGapTopDown: 0\n");
580 /* Go to the node with highest address in the tree. */
581 Node
= MmIterateLastNode((PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
);
583 /* Check if there is enough space after the last memory area. */
584 if (Node
->EndingAddress
<= AlignedAddress
)
586 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
587 return AlignedAddress
;
590 /* Traverse the tree from left to right. */
594 Node
= MmIteratePrevNode(Node
);
598 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
600 /* Check for overflow. */
601 if (AlignedAddress
> PreviousNode
->StartingAddress
)
604 if (Node
->EndingAddress
<= AlignedAddress
)
606 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
607 return AlignedAddress
;
613 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
615 /* Check for overflow. */
616 if (AlignedAddress
> PreviousNode
->StartingAddress
)
619 if (AlignedAddress
>= LowestAddress
)
621 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
622 return AlignedAddress
;
625 DPRINT("MmFindGapTopDown: 0\n");
632 PMMSUPPORT AddressSpace
,
634 ULONG_PTR Granularity
,
638 return MmFindGapTopDown(AddressSpace
, Length
, Granularity
);
640 return MmFindGapBottomUp(AddressSpace
, Length
, Granularity
);
645 PMMSUPPORT AddressSpace
,
648 PMEMORY_AREA Node
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
649 PMEMORY_AREA RightNeighbour
= NULL
;
650 PVOID LowestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ? MM_LOWEST_USER_ADDRESS
: MmSystemRangeStart
;
651 PVOID HighestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ?
652 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
654 MmVerifyMemoryAreas(AddressSpace
);
656 Address
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
658 if (LowestAddress
< MmSystemRangeStart
)
660 if (Address
>= MmSystemRangeStart
)
667 if (Address
< 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
;
707 * @name MmFreeMemoryArea
709 * Free an existing memory area.
711 * @param AddressSpace
712 * Address space to free the area from.
714 * Memory area we're about to free.
716 * Callback function for each freed page.
717 * @param FreePageContext
718 * Context passed to the callback function.
722 * @remarks Lock the address space before calling this function.
727 PMMSUPPORT AddressSpace
,
728 PMEMORY_AREA MemoryArea
,
729 PMM_FREE_PAGE_FUNC FreePage
,
730 PVOID FreePageContext
)
732 PMEMORY_AREA
*ParentReplace
;
735 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
736 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
738 if (Process
!= NULL
&&
739 Process
!= CurrentProcess
)
741 KeAttachProcess(&Process
->Pcb
);
744 EndAddress
= MM_ROUND_UP(MemoryArea
->EndingAddress
, PAGE_SIZE
);
745 for (Address
= (ULONG_PTR
)MemoryArea
->StartingAddress
;
746 Address
< (ULONG_PTR
)EndAddress
;
747 Address
+= PAGE_SIZE
)
749 if (MemoryArea
->Type
== MEMORY_AREA_IO_MAPPING
)
751 MmRawDeleteVirtualMapping((PVOID
)Address
);
755 BOOLEAN Dirty
= FALSE
;
756 SWAPENTRY SwapEntry
= 0;
759 if (MmIsPageSwapEntry(Process
, (PVOID
)Address
))
761 MmDeletePageFileMapping(Process
, (PVOID
)Address
, &SwapEntry
);
765 MmDeleteVirtualMapping(Process
, (PVOID
)Address
, FALSE
, &Dirty
, &Page
);
767 if (FreePage
!= NULL
)
769 FreePage(FreePageContext
, MemoryArea
, (PVOID
)Address
,
770 Page
, SwapEntry
, (BOOLEAN
)Dirty
);
775 if (Process
!= NULL
&&
776 Process
!= CurrentProcess
)
781 /* Remove the tree item. */
783 if (MemoryArea
->Parent
!= NULL
)
785 if (MemoryArea
->Parent
->LeftChild
== MemoryArea
)
786 ParentReplace
= &MemoryArea
->Parent
->LeftChild
;
788 ParentReplace
= &MemoryArea
->Parent
->RightChild
;
791 ParentReplace
= (PMEMORY_AREA
*)&AddressSpace
->WorkingSetExpansionLinks
.Flink
;
793 if (MemoryArea
->RightChild
== NULL
)
795 *ParentReplace
= MemoryArea
->LeftChild
;
796 if (MemoryArea
->LeftChild
)
797 MemoryArea
->LeftChild
->Parent
= MemoryArea
->Parent
;
801 if (MemoryArea
->RightChild
->LeftChild
== NULL
)
803 MemoryArea
->RightChild
->LeftChild
= MemoryArea
->LeftChild
;
804 if (MemoryArea
->LeftChild
)
805 MemoryArea
->LeftChild
->Parent
= MemoryArea
->RightChild
;
807 *ParentReplace
= MemoryArea
->RightChild
;
808 MemoryArea
->RightChild
->Parent
= MemoryArea
->Parent
;
812 PMEMORY_AREA LowestNode
;
814 LowestNode
= MemoryArea
->RightChild
->LeftChild
;
815 while (LowestNode
->LeftChild
!= NULL
)
816 LowestNode
= LowestNode
->LeftChild
;
818 LowestNode
->Parent
->LeftChild
= LowestNode
->RightChild
;
819 if (LowestNode
->RightChild
)
820 LowestNode
->RightChild
->Parent
= LowestNode
->Parent
;
822 LowestNode
->LeftChild
= MemoryArea
->LeftChild
;
823 if (MemoryArea
->LeftChild
)
824 MemoryArea
->LeftChild
->Parent
= LowestNode
;
826 LowestNode
->RightChild
= MemoryArea
->RightChild
;
827 MemoryArea
->RightChild
->Parent
= LowestNode
;
829 *ParentReplace
= LowestNode
;
830 LowestNode
->Parent
= MemoryArea
->Parent
;
835 ExFreePoolWithTag(MemoryArea
, TAG_MAREA
);
837 DPRINT("MmFreeMemoryAreaByNode() succeeded\n");
839 return STATUS_SUCCESS
;
843 * @name MmFreeMemoryAreaByPtr
845 * Free an existing memory area given a pointer inside it.
847 * @param AddressSpace
848 * Address space to free the area from.
850 * Address in the memory area we're about to free.
852 * Callback function for each freed page.
853 * @param FreePageContext
854 * Context passed to the callback function.
858 * @see MmFreeMemoryArea
860 * @todo Should we require the BaseAddress to be really the starting
861 * address of the memory area or is the current relaxed check
862 * (BaseAddress can point anywhere in the memory area) acceptable?
864 * @remarks Lock the address space before calling this function.
868 MmFreeMemoryAreaByPtr(
869 PMMSUPPORT AddressSpace
,
871 PMM_FREE_PAGE_FUNC FreePage
,
872 PVOID FreePageContext
)
874 PMEMORY_AREA MemoryArea
;
876 DPRINT("MmFreeMemoryArea(AddressSpace %p, BaseAddress %p, "
877 "FreePageContext %p)\n", AddressSpace
, BaseAddress
,
880 MmVerifyMemoryAreas(AddressSpace
);
882 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
884 if (MemoryArea
== NULL
)
886 KeBugCheck(MEMORY_MANAGEMENT
);
887 return(STATUS_UNSUCCESSFUL
);
890 return MmFreeMemoryArea(AddressSpace
, MemoryArea
, FreePage
, FreePageContext
);
894 * @name MmCreateMemoryArea
896 * Create a memory area.
898 * @param AddressSpace
899 * Address space to create the area in.
901 * Type of the memory area.
903 * Base address for the memory area we're about the create. On
904 * input it contains either 0 (auto-assign address) or preferred
905 * address. On output it contains the starting address of the
906 * newly created area.
908 * Length of the area to allocate.
910 * Protection attributes for the memory area.
912 * Receives a pointer to the memory area on successful exit.
916 * @remarks Lock the address space before calling this function.
920 MmCreateMemoryArea(PMMSUPPORT AddressSpace
,
925 PMEMORY_AREA
*Result
,
926 BOOLEAN FixedAddress
,
927 ULONG AllocationFlags
,
928 PHYSICAL_ADDRESS BoundaryAddressMultiple
)
933 PMEMORY_AREA MemoryArea
;
935 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
936 "*BaseAddress %p, Length %p, AllocationFlags %x, "
937 "FixedAddress %x, Result %p)\n",
938 Type
, BaseAddress
, *BaseAddress
, Length
, AllocationFlags
,
939 FixedAddress
, Result
);
941 MmVerifyMemoryAreas(AddressSpace
);
943 Granularity
= (MEMORY_AREA_VIRTUAL_MEMORY
== Type
? MM_VIRTMEM_GRANULARITY
: PAGE_SIZE
);
944 if ((*BaseAddress
) == 0 && !FixedAddress
)
946 tmpLength
= PAGE_ROUND_UP(Length
);
947 *BaseAddress
= MmFindGap(AddressSpace
,
950 (AllocationFlags
& MEM_TOP_DOWN
) == MEM_TOP_DOWN
);
951 if ((*BaseAddress
) == 0)
953 DPRINT("No suitable gap\n");
954 return STATUS_NO_MEMORY
;
959 tmpLength
= Length
+ ((ULONG_PTR
) *BaseAddress
960 - (ULONG_PTR
) MM_ROUND_DOWN(*BaseAddress
, Granularity
));
961 *BaseAddress
= MM_ROUND_DOWN(*BaseAddress
, Granularity
);
963 if (!MmGetAddressSpaceOwner(AddressSpace
) && *BaseAddress
< MmSystemRangeStart
)
965 return STATUS_ACCESS_VIOLATION
;
968 if (MmGetAddressSpaceOwner(AddressSpace
) &&
969 (ULONG_PTR
)(*BaseAddress
) + tmpLength
> (ULONG_PTR
)MmSystemRangeStart
)
971 return STATUS_ACCESS_VIOLATION
;
974 if (BoundaryAddressMultiple
.QuadPart
!= 0)
976 EndAddress
= ((char*)(*BaseAddress
)) + tmpLength
-1;
977 ASSERT(((ULONG_PTR
)*BaseAddress
/BoundaryAddressMultiple
.QuadPart
) == ((DWORD_PTR
)EndAddress
/BoundaryAddressMultiple
.QuadPart
));
980 if (MmLocateMemoryAreaByRegion(AddressSpace
,
984 DPRINT("Memory area already occupied\n");
985 return STATUS_CONFLICTING_ADDRESSES
;
990 // Is this a static memory area?
992 if (Type
& MEMORY_AREA_STATIC
)
995 // Use the static array instead of the pool
997 ASSERT(MiStaticMemoryAreaCount
< MI_STATIC_MEMORY_AREAS
);
998 MemoryArea
= &MiStaticMemoryAreas
[MiStaticMemoryAreaCount
++];
1003 // Allocate the memory area from nonpaged pool
1005 MemoryArea
= ExAllocatePoolWithTag(NonPagedPool
,
1006 sizeof(MEMORY_AREA
),
1010 RtlZeroMemory(MemoryArea
, sizeof(MEMORY_AREA
));
1011 MemoryArea
->Type
= Type
;
1012 MemoryArea
->StartingAddress
= *BaseAddress
;
1013 MemoryArea
->EndingAddress
= (PVOID
)((ULONG_PTR
)*BaseAddress
+ tmpLength
);
1014 MemoryArea
->Protect
= Protect
;
1015 MemoryArea
->Flags
= AllocationFlags
;
1016 //MemoryArea->LockCount = 0;
1017 MemoryArea
->PageOpCount
= 0;
1018 MemoryArea
->DeleteInProgress
= FALSE
;
1020 MmInsertMemoryArea(AddressSpace
, MemoryArea
);
1022 *Result
= MemoryArea
;
1024 DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress
);
1025 return STATUS_SUCCESS
;
1029 MmMapMemoryArea(PVOID BaseAddress
,
1037 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1041 Status
= MmRequestPageMemoryConsumer(Consumer
, TRUE
, &Page
);
1042 if (!NT_SUCCESS(Status
))
1044 DPRINT1("Unable to allocate page\n");
1045 KeBugCheck(MEMORY_MANAGEMENT
);
1047 Status
= MmCreateVirtualMapping (NULL
,
1048 (PVOID
)((ULONG_PTR
)BaseAddress
+ (i
* PAGE_SIZE
)),
1052 if (!NT_SUCCESS(Status
))
1054 DPRINT1("Unable to create virtual mapping\n");
1055 KeBugCheck(MEMORY_MANAGEMENT
);
1062 MmReleaseMemoryAreaIfDecommitted(PEPROCESS Process
,
1063 PMMSUPPORT AddressSpace
,
1066 PMEMORY_AREA MemoryArea
;
1071 MmVerifyMemoryAreas(AddressSpace
);
1073 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1074 if (MemoryArea
!= NULL
)
1076 Entry
= MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
.Flink
;
1078 while (Reserved
&& Entry
!= &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
)
1080 Region
= CONTAINING_RECORD(Entry
, MM_REGION
, RegionListEntry
);
1081 Reserved
= (MEM_RESERVE
== Region
->Type
);
1082 Entry
= Entry
->Flink
;
1087 MmFreeVirtualMemory(Process
, MemoryArea
);