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 #if defined (ALLOC_PRAGMA)
49 #pragma alloc_text(INIT, MmInitMemoryAreas)
52 MEMORY_AREA MiStaticMemoryAreas
[MI_STATIC_MEMORY_AREAS
];
53 ULONG MiStaticMemoryAreaCount
;
55 /* #define VALIDATE_MEMORY_AREAS */
57 /* FUNCTIONS *****************************************************************/
60 * @name MmIterateFirstNode
63 * Head node of the MEMORY_AREA tree.
65 * @return The leftmost MEMORY_AREA node (ie. the one with lowest
69 static PMEMORY_AREA
MmIterateFirstNode(PMEMORY_AREA Node
)
71 while (Node
->LeftChild
!= NULL
)
72 Node
= Node
->LeftChild
;
78 * @name MmIterateNextNode
81 * Current node in the tree.
83 * @return Next node in the tree (sorted by address).
86 static PMEMORY_AREA
MmIterateNextNode(PMEMORY_AREA Node
)
88 if (Node
->RightChild
!= NULL
)
90 Node
= Node
->RightChild
;
91 while (Node
->LeftChild
!= NULL
)
92 Node
= Node
->LeftChild
;
96 PMEMORY_AREA TempNode
= NULL
;
100 /* Check if we're at the end of tree. */
101 if (Node
->Parent
== NULL
)
107 while (TempNode
== Node
->RightChild
);
113 * @name MmIterateLastNode
116 * Head node of the MEMORY_AREA tree.
118 * @return The rightmost MEMORY_AREA node (ie. the one with highest
122 static PMEMORY_AREA
MmIterateLastNode(PMEMORY_AREA Node
)
124 while (Node
->RightChild
!= NULL
)
125 Node
= Node
->RightChild
;
131 * @name MmIteratePreviousNode
134 * Current node in the tree.
136 * @return Previous node in the tree (sorted by address).
139 static PMEMORY_AREA
MmIteratePrevNode(PMEMORY_AREA Node
)
141 if (Node
->LeftChild
!= NULL
)
143 Node
= Node
->LeftChild
;
144 while (Node
->RightChild
!= NULL
)
145 Node
= Node
->RightChild
;
149 PMEMORY_AREA TempNode
= NULL
;
153 /* Check if we're at the end of tree. */
154 if (Node
->Parent
== NULL
)
160 while (TempNode
== Node
->LeftChild
);
165 #ifdef VALIDATE_MEMORY_AREAS
166 static VOID
MmVerifyMemoryAreas(PMMSUPPORT AddressSpace
)
170 ASSERT(AddressSpace
!= NULL
);
172 /* Special case for empty tree. */
173 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
176 /* Traverse the tree from left to right. */
177 for (Node
= MmIterateFirstNode(AddressSpace
->WorkingSetExpansionLinks
.Flink
);
179 Node
= MmIterateNextNode(Node
))
181 /* FiN: The starting address can be NULL if someone explicitely asks
182 * for NULL address. */
183 ASSERT(Node
->StartingAddress
== NULL
);
184 ASSERT(Node
->EndingAddress
>= Node
->StartingAddress
);
188 #define MmVerifyMemoryAreas(x)
192 MmDumpMemoryAreas(PMMSUPPORT AddressSpace
)
196 DbgPrint("MmDumpMemoryAreas()\n");
198 /* Special case for empty tree. */
199 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
202 /* Traverse the tree from left to right. */
203 for (Node
= MmIterateFirstNode((PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
);
205 Node
= MmIterateNextNode(Node
))
207 DbgPrint("Start %p End %p Protect %x Flags %x\n",
208 Node
->StartingAddress
, Node
->EndingAddress
,
209 Node
->Protect
, Node
->Flags
);
212 DbgPrint("Finished MmDumpMemoryAreas()\n");
216 MmLocateMemoryAreaByAddress(
217 PMMSUPPORT AddressSpace
,
220 PMEMORY_AREA Node
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
222 DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
223 AddressSpace
, Address
);
225 MmVerifyMemoryAreas(AddressSpace
);
229 if (Address
< Node
->StartingAddress
)
230 Node
= Node
->LeftChild
;
231 else if (Address
>= Node
->EndingAddress
)
232 Node
= Node
->RightChild
;
235 DPRINT("MmLocateMemoryAreaByAddress(%p): %p [%p - %p]\n",
236 Address
, Node
, Node
->StartingAddress
, Node
->EndingAddress
);
241 DPRINT("MmLocateMemoryAreaByAddress(%p): 0\n", Address
);
246 MmLocateMemoryAreaByRegion(
247 PMMSUPPORT AddressSpace
,
252 PVOID Extent
= (PVOID
)((ULONG_PTR
)Address
+ Length
);
254 MmVerifyMemoryAreas(AddressSpace
);
256 /* Special case for empty tree. */
257 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
260 /* Traverse the tree from left to right. */
261 for (Node
= MmIterateFirstNode((PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
);
263 Node
= MmIterateNextNode(Node
))
265 if (Node
->StartingAddress
>= Address
&&
266 Node
->StartingAddress
< Extent
)
268 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
269 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
270 Node
->EndingAddress
);
273 if (Node
->EndingAddress
> Address
&&
274 Node
->EndingAddress
< Extent
)
276 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
277 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
278 Node
->EndingAddress
);
281 if (Node
->StartingAddress
<= Address
&&
282 Node
->EndingAddress
>= Extent
)
284 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
285 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
286 Node
->EndingAddress
);
289 if (Node
->StartingAddress
>= Extent
)
291 DPRINT("Finished MmLocateMemoryAreaByRegion() = NULL\n");
300 * @name MmCompressHelper
302 * This is helper of MmRebalanceTree. Performs a compression transformation
303 * count times, starting at root.
308 PMMSUPPORT AddressSpace
,
311 PMEMORY_AREA Root
= NULL
;
312 PMEMORY_AREA Red
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
313 PMEMORY_AREA Black
= Red
->LeftChild
;
318 Root
->LeftChild
= Black
;
320 AddressSpace
->WorkingSetExpansionLinks
.Flink
= (PVOID
)Black
;
321 Black
->Parent
= Root
;
322 Red
->LeftChild
= Black
->RightChild
;
323 if (Black
->RightChild
)
324 Black
->RightChild
->Parent
= Red
;
325 Black
->RightChild
= Red
;
331 Red
= Root
->LeftChild
;
332 Black
= Red
->LeftChild
;
338 * @name MmRebalanceTree
340 * Rebalance a memory area tree using the Tree->Vine->Balanced Tree
341 * method described in libavl documentation in chapter 4.12.
342 * (http://www.stanford.edu/~blp/avl/libavl.html/)
347 PMMSUPPORT AddressSpace
)
349 PMEMORY_AREA PreviousNode
;
350 PMEMORY_AREA CurrentNode
;
351 PMEMORY_AREA TempNode
;
353 ULONG Vine
; /* Number of nodes in main vine. */
354 ULONG Leaves
; /* Nodes in incomplete bottom level, if any. */
355 INT Height
; /* Height of produced balanced tree. */
357 /* Transform the tree into Vine. */
360 CurrentNode
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
361 while (CurrentNode
!= NULL
)
363 if (CurrentNode
->RightChild
== NULL
)
365 PreviousNode
= CurrentNode
;
366 CurrentNode
= CurrentNode
->LeftChild
;
371 TempNode
= CurrentNode
->RightChild
;
373 CurrentNode
->RightChild
= TempNode
->LeftChild
;
374 if (TempNode
->LeftChild
)
375 TempNode
->LeftChild
->Parent
= CurrentNode
;
377 TempNode
->LeftChild
= CurrentNode
;
378 CurrentNode
->Parent
= TempNode
;
380 CurrentNode
= TempNode
;
382 if (PreviousNode
!= NULL
)
383 PreviousNode
->LeftChild
= TempNode
;
385 AddressSpace
->WorkingSetExpansionLinks
.Flink
= (PVOID
)TempNode
;
386 TempNode
->Parent
= PreviousNode
;
390 /* Transform Vine back into a balanced tree. */
392 Leaves
= NodeCount
+ 1;
395 ULONG Next
= Leaves
& (Leaves
- 1);
400 Leaves
= NodeCount
+ 1 - Leaves
;
402 MmCompressHelper(AddressSpace
, Leaves
);
404 Vine
= NodeCount
- Leaves
;
405 Height
= 1 + (Leaves
> 0);
408 MmCompressHelper(AddressSpace
, Vine
/ 2);
416 PMMSUPPORT AddressSpace
,
420 PMEMORY_AREA PreviousNode
;
423 MmVerifyMemoryAreas(AddressSpace
);
425 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
427 AddressSpace
->WorkingSetExpansionLinks
.Flink
= (PVOID
)marea
;
428 marea
->LeftChild
= marea
->RightChild
= marea
->Parent
= NULL
;
432 Node
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
435 DPRINT("marea->EndingAddress: %p Node->StartingAddress: %p\n",
436 marea
->EndingAddress
, Node
->StartingAddress
);
437 DPRINT("marea->StartingAddress: %p Node->EndingAddress: %p\n",
438 marea
->StartingAddress
, Node
->EndingAddress
);
439 ASSERT(marea
->EndingAddress
<= Node
->StartingAddress
||
440 marea
->StartingAddress
>= Node
->EndingAddress
);
441 ASSERT(marea
->StartingAddress
!= Node
->StartingAddress
);
445 if (marea
->StartingAddress
< Node
->StartingAddress
)
446 Node
= Node
->LeftChild
;
448 Node
= Node
->RightChild
;
455 MmRebalanceTree(AddressSpace
);
456 PreviousNode
= Node
->Parent
;
460 while (Node
!= NULL
);
462 marea
->LeftChild
= marea
->RightChild
= NULL
;
463 marea
->Parent
= PreviousNode
;
464 if (marea
->StartingAddress
< PreviousNode
->StartingAddress
)
465 PreviousNode
->LeftChild
= marea
;
467 PreviousNode
->RightChild
= marea
;
472 PMMSUPPORT AddressSpace
,
474 ULONG_PTR Granularity
)
476 PVOID LowestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ? MM_LOWEST_USER_ADDRESS
: MmSystemRangeStart
;
477 PVOID HighestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ?
478 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
479 PVOID AlignedAddress
;
481 PMEMORY_AREA FirstNode
;
482 PMEMORY_AREA PreviousNode
;
484 MmVerifyMemoryAreas(AddressSpace
);
486 DPRINT("LowestAddress: %p HighestAddress: %p\n",
487 LowestAddress
, HighestAddress
);
489 AlignedAddress
= MM_ROUND_UP(LowestAddress
, Granularity
);
491 /* Special case for empty tree. */
492 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
494 if ((ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
496 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
497 return AlignedAddress
;
499 DPRINT("MmFindGapBottomUp: 0\n");
503 /* Go to the node with lowest address in the tree. */
504 FirstNode
= Node
= MmIterateFirstNode((PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
);
506 /* Traverse the tree from left to right. */
510 Node
= MmIterateNextNode(Node
);
514 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
515 if (Node
->StartingAddress
> AlignedAddress
&&
516 (ULONG_PTR
)Node
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
518 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
519 return AlignedAddress
;
525 /* Check if there is enough space after the last memory area. */
526 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
527 if ((ULONG_PTR
)HighestAddress
> (ULONG_PTR
)AlignedAddress
&&
528 (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
530 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
531 return AlignedAddress
;
534 /* Check if there is enough space before the first memory area. */
535 AlignedAddress
= MM_ROUND_UP(LowestAddress
, Granularity
);
536 if (FirstNode
->StartingAddress
> AlignedAddress
&&
537 (ULONG_PTR
)FirstNode
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
539 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
540 return AlignedAddress
;
543 DPRINT("MmFindGapBottomUp: 0\n");
550 PMMSUPPORT AddressSpace
,
552 ULONG_PTR Granularity
)
554 PVOID LowestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ? MM_LOWEST_USER_ADDRESS
: MmSystemRangeStart
;
555 PVOID HighestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ?
556 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
557 PVOID AlignedAddress
;
559 PMEMORY_AREA PreviousNode
;
561 MmVerifyMemoryAreas(AddressSpace
);
563 DPRINT("LowestAddress: %p HighestAddress: %p\n",
564 LowestAddress
, HighestAddress
);
566 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)HighestAddress
- Length
+ 1, Granularity
);
568 /* Check for overflow. */
569 if (AlignedAddress
> HighestAddress
)
572 /* Special case for empty tree. */
573 if (AddressSpace
->WorkingSetExpansionLinks
.Flink
== NULL
)
575 if (AlignedAddress
>= LowestAddress
)
577 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
578 return AlignedAddress
;
580 DPRINT("MmFindGapTopDown: 0\n");
584 /* Go to the node with highest address in the tree. */
585 Node
= MmIterateLastNode((PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
);
587 /* Check if there is enough space after the last memory area. */
588 if (Node
->EndingAddress
<= AlignedAddress
)
590 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
591 return AlignedAddress
;
594 /* Traverse the tree from left to right. */
598 Node
= MmIteratePrevNode(Node
);
602 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
604 /* Check for overflow. */
605 if (AlignedAddress
> PreviousNode
->StartingAddress
)
608 if (Node
->EndingAddress
<= AlignedAddress
)
610 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
611 return AlignedAddress
;
617 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
619 /* Check for overflow. */
620 if (AlignedAddress
> PreviousNode
->StartingAddress
)
623 if (AlignedAddress
>= LowestAddress
)
625 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
626 return AlignedAddress
;
629 DPRINT("MmFindGapTopDown: 0\n");
636 PMMSUPPORT AddressSpace
,
638 ULONG_PTR Granularity
,
642 return MmFindGapTopDown(AddressSpace
, Length
, Granularity
);
644 return MmFindGapBottomUp(AddressSpace
, Length
, Granularity
);
649 PMMSUPPORT AddressSpace
,
652 PMEMORY_AREA Node
= (PMEMORY_AREA
)AddressSpace
->WorkingSetExpansionLinks
.Flink
;
653 PMEMORY_AREA RightNeighbour
= NULL
;
654 PVOID LowestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ? MM_LOWEST_USER_ADDRESS
: MmSystemRangeStart
;
655 PVOID HighestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ?
656 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
658 MmVerifyMemoryAreas(AddressSpace
);
660 Address
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
662 if (LowestAddress
< MmSystemRangeStart
)
664 if (Address
>= MmSystemRangeStart
)
671 if (Address
< LowestAddress
)
679 if (Address
< Node
->StartingAddress
)
681 RightNeighbour
= Node
;
682 Node
= Node
->LeftChild
;
684 else if (Address
>= Node
->EndingAddress
)
686 Node
= Node
->RightChild
;
690 DPRINT("MmFindGapAtAddress: 0\n");
697 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
698 (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
);
699 return (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
;
703 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
704 (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
);
705 return (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
;
711 * @name MmFreeMemoryArea
713 * Free an existing memory area.
715 * @param AddressSpace
716 * Address space to free the area from.
718 * Memory area we're about to free.
720 * Callback function for each freed page.
721 * @param FreePageContext
722 * Context passed to the callback function.
726 * @remarks Lock the address space before calling this function.
731 PMMSUPPORT AddressSpace
,
732 PMEMORY_AREA MemoryArea
,
733 PMM_FREE_PAGE_FUNC FreePage
,
734 PVOID FreePageContext
)
736 PMEMORY_AREA
*ParentReplace
;
739 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
740 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
742 if (Process
!= NULL
&&
743 Process
!= CurrentProcess
)
745 KeAttachProcess(&Process
->Pcb
);
748 EndAddress
= MM_ROUND_UP(MemoryArea
->EndingAddress
, PAGE_SIZE
);
749 for (Address
= (ULONG_PTR
)MemoryArea
->StartingAddress
;
750 Address
< (ULONG_PTR
)EndAddress
;
751 Address
+= PAGE_SIZE
)
753 if (MemoryArea
->Type
== MEMORY_AREA_IO_MAPPING
)
755 MmRawDeleteVirtualMapping((PVOID
)Address
);
759 BOOLEAN Dirty
= FALSE
;
760 SWAPENTRY SwapEntry
= 0;
763 if (MmIsPageSwapEntry(Process
, (PVOID
)Address
))
765 MmDeletePageFileMapping(Process
, (PVOID
)Address
, &SwapEntry
);
769 MmDeleteVirtualMapping(Process
, (PVOID
)Address
, FALSE
, &Dirty
, &Page
);
771 if (FreePage
!= NULL
)
773 FreePage(FreePageContext
, MemoryArea
, (PVOID
)Address
,
774 Page
, SwapEntry
, (BOOLEAN
)Dirty
);
779 if (Process
!= NULL
&&
780 Process
!= CurrentProcess
)
785 /* Remove the tree item. */
787 if (MemoryArea
->Parent
!= NULL
)
789 if (MemoryArea
->Parent
->LeftChild
== MemoryArea
)
790 ParentReplace
= &MemoryArea
->Parent
->LeftChild
;
792 ParentReplace
= &MemoryArea
->Parent
->RightChild
;
795 ParentReplace
= (PMEMORY_AREA
*)&AddressSpace
->WorkingSetExpansionLinks
.Flink
;
797 if (MemoryArea
->RightChild
== NULL
)
799 *ParentReplace
= MemoryArea
->LeftChild
;
800 if (MemoryArea
->LeftChild
)
801 MemoryArea
->LeftChild
->Parent
= MemoryArea
->Parent
;
805 if (MemoryArea
->RightChild
->LeftChild
== NULL
)
807 MemoryArea
->RightChild
->LeftChild
= MemoryArea
->LeftChild
;
808 if (MemoryArea
->LeftChild
)
809 MemoryArea
->LeftChild
->Parent
= MemoryArea
->RightChild
;
811 *ParentReplace
= MemoryArea
->RightChild
;
812 MemoryArea
->RightChild
->Parent
= MemoryArea
->Parent
;
816 PMEMORY_AREA LowestNode
;
818 LowestNode
= MemoryArea
->RightChild
->LeftChild
;
819 while (LowestNode
->LeftChild
!= NULL
)
820 LowestNode
= LowestNode
->LeftChild
;
822 LowestNode
->Parent
->LeftChild
= LowestNode
->RightChild
;
823 if (LowestNode
->RightChild
)
824 LowestNode
->RightChild
->Parent
= LowestNode
->Parent
;
826 LowestNode
->LeftChild
= MemoryArea
->LeftChild
;
827 if (MemoryArea
->LeftChild
)
828 MemoryArea
->LeftChild
->Parent
= LowestNode
;
830 LowestNode
->RightChild
= MemoryArea
->RightChild
;
831 MemoryArea
->RightChild
->Parent
= LowestNode
;
833 *ParentReplace
= LowestNode
;
834 LowestNode
->Parent
= MemoryArea
->Parent
;
839 ExFreePoolWithTag(MemoryArea
, TAG_MAREA
);
841 DPRINT("MmFreeMemoryAreaByNode() succeeded\n");
843 return STATUS_SUCCESS
;
847 * @name MmFreeMemoryAreaByPtr
849 * Free an existing memory area given a pointer inside it.
851 * @param AddressSpace
852 * Address space to free the area from.
854 * Address in the memory area we're about to free.
856 * Callback function for each freed page.
857 * @param FreePageContext
858 * Context passed to the callback function.
862 * @see MmFreeMemoryArea
864 * @todo Should we require the BaseAddress to be really the starting
865 * address of the memory area or is the current relaxed check
866 * (BaseAddress can point anywhere in the memory area) acceptable?
868 * @remarks Lock the address space before calling this function.
872 MmFreeMemoryAreaByPtr(
873 PMMSUPPORT AddressSpace
,
875 PMM_FREE_PAGE_FUNC FreePage
,
876 PVOID FreePageContext
)
878 PMEMORY_AREA MemoryArea
;
880 DPRINT("MmFreeMemoryArea(AddressSpace %p, BaseAddress %p, "
881 "FreePageContext %p)\n", AddressSpace
, BaseAddress
,
884 MmVerifyMemoryAreas(AddressSpace
);
886 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
888 if (MemoryArea
== NULL
)
890 KeBugCheck(MEMORY_MANAGEMENT
);
891 return(STATUS_UNSUCCESSFUL
);
894 return MmFreeMemoryArea(AddressSpace
, MemoryArea
, FreePage
, FreePageContext
);
898 * @name MmCreateMemoryArea
900 * Create a memory area.
902 * @param AddressSpace
903 * Address space to create the area in.
905 * Type of the memory area.
907 * Base address for the memory area we're about the create. On
908 * input it contains either 0 (auto-assign address) or preferred
909 * address. On output it contains the starting address of the
910 * newly created area.
912 * Length of the area to allocate.
914 * Protection attributes for the memory area.
916 * Receives a pointer to the memory area on successful exit.
920 * @remarks Lock the address space before calling this function.
924 MmCreateMemoryArea(PMMSUPPORT AddressSpace
,
929 PMEMORY_AREA
*Result
,
930 BOOLEAN FixedAddress
,
931 ULONG AllocationFlags
,
932 PHYSICAL_ADDRESS BoundaryAddressMultiple
)
937 PMEMORY_AREA MemoryArea
;
939 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
940 "*BaseAddress %p, Length %p, AllocationFlags %x, "
941 "FixedAddress %x, Result %p)\n",
942 Type
, BaseAddress
, *BaseAddress
, Length
, AllocationFlags
,
943 FixedAddress
, Result
);
945 MmVerifyMemoryAreas(AddressSpace
);
947 Granularity
= (MEMORY_AREA_VIRTUAL_MEMORY
== Type
? MM_VIRTMEM_GRANULARITY
: PAGE_SIZE
);
948 if ((*BaseAddress
) == 0 && !FixedAddress
)
950 tmpLength
= PAGE_ROUND_UP(Length
);
951 *BaseAddress
= MmFindGap(AddressSpace
,
954 (AllocationFlags
& MEM_TOP_DOWN
) == MEM_TOP_DOWN
);
955 if ((*BaseAddress
) == 0)
957 DPRINT("No suitable gap\n");
958 return STATUS_NO_MEMORY
;
963 tmpLength
= Length
+ ((ULONG_PTR
) *BaseAddress
964 - (ULONG_PTR
) MM_ROUND_DOWN(*BaseAddress
, Granularity
));
965 *BaseAddress
= MM_ROUND_DOWN(*BaseAddress
, Granularity
);
967 if (!MmGetAddressSpaceOwner(AddressSpace
) && *BaseAddress
< MmSystemRangeStart
)
969 return STATUS_ACCESS_VIOLATION
;
972 if (MmGetAddressSpaceOwner(AddressSpace
) &&
973 (ULONG_PTR
)(*BaseAddress
) + tmpLength
> (ULONG_PTR
)MmSystemRangeStart
)
975 return STATUS_ACCESS_VIOLATION
;
978 if (BoundaryAddressMultiple
.QuadPart
!= 0)
980 EndAddress
= ((char*)(*BaseAddress
)) + tmpLength
-1;
981 ASSERT(((ULONG_PTR
)*BaseAddress
/BoundaryAddressMultiple
.QuadPart
) == ((DWORD_PTR
)EndAddress
/BoundaryAddressMultiple
.QuadPart
));
984 if (MmLocateMemoryAreaByRegion(AddressSpace
,
988 DPRINT("Memory area already occupied\n");
989 return STATUS_CONFLICTING_ADDRESSES
;
994 // Is this a static memory area?
996 if (Type
& MEMORY_AREA_STATIC
)
999 // Use the static array instead of the pool
1001 ASSERT(MiStaticMemoryAreaCount
< MI_STATIC_MEMORY_AREAS
);
1002 MemoryArea
= &MiStaticMemoryAreas
[MiStaticMemoryAreaCount
++];
1007 // Allocate the memory area from nonpaged pool
1009 MemoryArea
= ExAllocatePoolWithTag(NonPagedPool
,
1010 sizeof(MEMORY_AREA
),
1014 RtlZeroMemory(MemoryArea
, sizeof(MEMORY_AREA
));
1015 MemoryArea
->Type
= Type
;
1016 MemoryArea
->StartingAddress
= *BaseAddress
;
1017 MemoryArea
->EndingAddress
= (PVOID
)((ULONG_PTR
)*BaseAddress
+ tmpLength
);
1018 MemoryArea
->Protect
= Protect
;
1019 MemoryArea
->Flags
= AllocationFlags
;
1020 //MemoryArea->LockCount = 0;
1021 MemoryArea
->PageOpCount
= 0;
1022 MemoryArea
->DeleteInProgress
= FALSE
;
1024 MmInsertMemoryArea(AddressSpace
, MemoryArea
);
1026 *Result
= MemoryArea
;
1028 DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress
);
1029 return STATUS_SUCCESS
;
1033 MmMapMemoryArea(PVOID BaseAddress
,
1041 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1045 Status
= MmRequestPageMemoryConsumer(Consumer
, TRUE
, &Page
);
1046 if (!NT_SUCCESS(Status
))
1048 DPRINT1("Unable to allocate page\n");
1049 KeBugCheck(MEMORY_MANAGEMENT
);
1051 Status
= MmCreateVirtualMapping (NULL
,
1052 (PVOID
)((ULONG_PTR
)BaseAddress
+ (i
* PAGE_SIZE
)),
1056 if (!NT_SUCCESS(Status
))
1058 DPRINT1("Unable to create virtual mapping\n");
1059 KeBugCheck(MEMORY_MANAGEMENT
);
1066 MmReleaseMemoryAreaIfDecommitted(PEPROCESS Process
,
1067 PMMSUPPORT AddressSpace
,
1070 PMEMORY_AREA MemoryArea
;
1075 MmVerifyMemoryAreas(AddressSpace
);
1077 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1078 if (MemoryArea
!= NULL
)
1080 Entry
= MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
.Flink
;
1082 while (Reserved
&& Entry
!= &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
)
1084 Region
= CONTAINING_RECORD(Entry
, MM_REGION
, RegionListEntry
);
1085 Reserved
= (MEM_RESERVE
== Region
->Type
);
1086 Entry
= Entry
->Flink
;
1091 MmFreeVirtualMemory(Process
, MemoryArea
);