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 *****************************************************************/
46 #include <internal/debug.h>
48 #if defined (ALLOC_PRAGMA)
49 #pragma alloc_text(INIT, MmInitMemoryAreas)
52 /* #define VALIDATE_MEMORY_AREAS */
54 /* FUNCTIONS *****************************************************************/
57 * @name MmIterateFirstNode
60 * Head node of the MEMORY_AREA tree.
62 * @return The leftmost MEMORY_AREA node (ie. the one with lowest
66 static PMEMORY_AREA
MmIterateFirstNode(PMEMORY_AREA Node
)
68 while (Node
->LeftChild
!= NULL
)
69 Node
= Node
->LeftChild
;
75 * @name MmIterateNextNode
78 * Current node in the tree.
80 * @return Next node in the tree (sorted by address).
83 static PMEMORY_AREA
MmIterateNextNode(PMEMORY_AREA Node
)
85 if (Node
->RightChild
!= NULL
)
87 Node
= Node
->RightChild
;
88 while (Node
->LeftChild
!= NULL
)
89 Node
= Node
->LeftChild
;
93 PMEMORY_AREA TempNode
= NULL
;
97 /* Check if we're at the end of tree. */
98 if (Node
->Parent
== NULL
)
104 while (TempNode
== Node
->RightChild
);
110 * @name MmIterateLastNode
113 * Head node of the MEMORY_AREA tree.
115 * @return The rightmost MEMORY_AREA node (ie. the one with highest
119 static PMEMORY_AREA
MmIterateLastNode(PMEMORY_AREA Node
)
121 while (Node
->RightChild
!= NULL
)
122 Node
= Node
->RightChild
;
128 * @name MmIteratePreviousNode
131 * Current node in the tree.
133 * @return Previous node in the tree (sorted by address).
136 static PMEMORY_AREA
MmIteratePrevNode(PMEMORY_AREA Node
)
138 if (Node
->LeftChild
!= NULL
)
140 Node
= Node
->LeftChild
;
141 while (Node
->RightChild
!= NULL
)
142 Node
= Node
->RightChild
;
146 PMEMORY_AREA TempNode
= NULL
;
150 /* Check if we're at the end of tree. */
151 if (Node
->Parent
== NULL
)
157 while (TempNode
== Node
->LeftChild
);
162 #ifdef VALIDATE_MEMORY_AREAS
163 static VOID
MmVerifyMemoryAreas(PMADDRESS_SPACE AddressSpace
)
167 ASSERT(AddressSpace
!= NULL
);
169 /* Special case for empty tree. */
170 if (AddressSpace
->MemoryAreaRoot
== NULL
)
173 /* Traverse the tree from left to right. */
174 for (Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
176 Node
= MmIterateNextNode(Node
))
178 /* FiN: The starting address can be NULL if someone explicitely asks
179 * for NULL address. */
180 ASSERT(Node
->StartingAddress
== NULL
);
181 ASSERT(Node
->EndingAddress
>= Node
->StartingAddress
);
185 #define MmVerifyMemoryAreas(x)
189 MmDumpMemoryAreas(PMADDRESS_SPACE AddressSpace
)
193 DbgPrint("MmDumpMemoryAreas()\n");
195 /* Special case for empty tree. */
196 if (AddressSpace
->MemoryAreaRoot
== NULL
)
199 /* Traverse the tree from left to right. */
200 for (Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
202 Node
= MmIterateNextNode(Node
))
204 DbgPrint("Start %p End %p Protect %x Flags %x\n",
205 Node
->StartingAddress
, Node
->EndingAddress
,
206 Node
->Protect
, Node
->Flags
);
209 DbgPrint("Finished MmDumpMemoryAreas()\n");
213 MmLocateMemoryAreaByAddress(
214 PMADDRESS_SPACE AddressSpace
,
217 PMEMORY_AREA Node
= AddressSpace
->MemoryAreaRoot
;
219 DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
220 AddressSpace
, Address
);
222 MmVerifyMemoryAreas(AddressSpace
);
226 if (Address
< Node
->StartingAddress
)
227 Node
= Node
->LeftChild
;
228 else if (Address
>= Node
->EndingAddress
)
229 Node
= Node
->RightChild
;
232 DPRINT("MmLocateMemoryAreaByAddress(%p): %p [%p - %p]\n",
233 Address
, Node
, Node
->StartingAddress
, Node
->EndingAddress
);
238 DPRINT("MmLocateMemoryAreaByAddress(%p): 0\n", Address
);
243 MmLocateMemoryAreaByRegion(
244 PMADDRESS_SPACE AddressSpace
,
249 PVOID Extent
= (PVOID
)((ULONG_PTR
)Address
+ Length
);
251 MmVerifyMemoryAreas(AddressSpace
);
253 /* Special case for empty tree. */
254 if (AddressSpace
->MemoryAreaRoot
== NULL
)
257 /* Traverse the tree from left to right. */
258 for (Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
260 Node
= MmIterateNextNode(Node
))
262 if (Node
->StartingAddress
>= Address
&&
263 Node
->StartingAddress
< Extent
)
265 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
266 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
267 Node
->EndingAddress
);
270 if (Node
->EndingAddress
> Address
&&
271 Node
->EndingAddress
< Extent
)
273 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
274 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
275 Node
->EndingAddress
);
278 if (Node
->StartingAddress
<= Address
&&
279 Node
->EndingAddress
>= Extent
)
281 DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
282 Address
, (ULONG_PTR
)Address
+ Length
, Node
->StartingAddress
,
283 Node
->EndingAddress
);
286 if (Node
->StartingAddress
>= Extent
)
288 DPRINT("Finished MmLocateMemoryAreaByRegion() = NULL\n");
297 * @name MmCompressHelper
299 * This is helper of MmRebalanceTree. Performs a compression transformation
300 * count times, starting at root.
305 PMADDRESS_SPACE AddressSpace
,
308 PMEMORY_AREA Root
= NULL
;
309 PMEMORY_AREA Red
= AddressSpace
->MemoryAreaRoot
;
310 PMEMORY_AREA Black
= Red
->LeftChild
;
315 Root
->LeftChild
= Black
;
317 AddressSpace
->MemoryAreaRoot
= Black
;
318 Black
->Parent
= Root
;
319 Red
->LeftChild
= Black
->RightChild
;
320 if (Black
->RightChild
)
321 Black
->RightChild
->Parent
= Red
;
322 Black
->RightChild
= Red
;
328 Red
= Root
->LeftChild
;
329 Black
= Red
->LeftChild
;
335 * @name MmRebalanceTree
337 * Rebalance a memory area tree using the Tree->Vine->Balanced Tree
338 * method described in libavl documentation in chapter 4.12.
339 * (http://www.stanford.edu/~blp/avl/libavl.html/)
344 PMADDRESS_SPACE AddressSpace
)
346 PMEMORY_AREA PreviousNode
;
347 PMEMORY_AREA CurrentNode
;
348 PMEMORY_AREA TempNode
;
350 ULONG Vine
; /* Number of nodes in main vine. */
351 ULONG Leaves
; /* Nodes in incomplete bottom level, if any. */
352 INT Height
; /* Height of produced balanced tree. */
354 /* Transform the tree into Vine. */
357 CurrentNode
= AddressSpace
->MemoryAreaRoot
;
358 while (CurrentNode
!= NULL
)
360 if (CurrentNode
->RightChild
== NULL
)
362 PreviousNode
= CurrentNode
;
363 CurrentNode
= CurrentNode
->LeftChild
;
368 TempNode
= CurrentNode
->RightChild
;
370 CurrentNode
->RightChild
= TempNode
->LeftChild
;
371 if (TempNode
->LeftChild
)
372 TempNode
->LeftChild
->Parent
= CurrentNode
;
374 TempNode
->LeftChild
= CurrentNode
;
375 CurrentNode
->Parent
= TempNode
;
377 CurrentNode
= TempNode
;
379 if (PreviousNode
!= NULL
)
380 PreviousNode
->LeftChild
= TempNode
;
382 AddressSpace
->MemoryAreaRoot
= TempNode
;
383 TempNode
->Parent
= PreviousNode
;
387 /* Transform Vine back into a balanced tree. */
389 Leaves
= NodeCount
+ 1;
392 ULONG Next
= Leaves
& (Leaves
- 1);
397 Leaves
= NodeCount
+ 1 - Leaves
;
399 MmCompressHelper(AddressSpace
, Leaves
);
401 Vine
= NodeCount
- Leaves
;
402 Height
= 1 + (Leaves
> 0);
405 MmCompressHelper(AddressSpace
, Vine
/ 2);
413 PMADDRESS_SPACE AddressSpace
,
417 PMEMORY_AREA PreviousNode
;
420 MmVerifyMemoryAreas(AddressSpace
);
422 if (AddressSpace
->MemoryAreaRoot
== NULL
)
424 AddressSpace
->MemoryAreaRoot
= marea
;
425 marea
->LeftChild
= marea
->RightChild
= marea
->Parent
= NULL
;
429 Node
= AddressSpace
->MemoryAreaRoot
;
432 DPRINT("marea->EndingAddress: %p Node->StartingAddress: %p\n",
433 marea
->EndingAddress
, Node
->StartingAddress
);
434 DPRINT("marea->StartingAddress: %p Node->EndingAddress: %p\n",
435 marea
->StartingAddress
, Node
->EndingAddress
);
436 ASSERT(marea
->EndingAddress
<= Node
->StartingAddress
||
437 marea
->StartingAddress
>= Node
->EndingAddress
);
438 ASSERT(marea
->StartingAddress
!= Node
->StartingAddress
);
442 if (marea
->StartingAddress
< Node
->StartingAddress
)
443 Node
= Node
->LeftChild
;
445 Node
= Node
->RightChild
;
452 MmRebalanceTree(AddressSpace
);
453 PreviousNode
= Node
->Parent
;
457 while (Node
!= NULL
);
459 marea
->LeftChild
= marea
->RightChild
= NULL
;
460 marea
->Parent
= PreviousNode
;
461 if (marea
->StartingAddress
< PreviousNode
->StartingAddress
)
462 PreviousNode
->LeftChild
= marea
;
464 PreviousNode
->RightChild
= marea
;
469 PMADDRESS_SPACE AddressSpace
,
471 ULONG_PTR Granularity
)
473 PVOID LowestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ? MM_LOWEST_USER_ADDRESS
: MmSystemRangeStart
;
474 PVOID HighestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ?
475 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
476 PVOID AlignedAddress
;
478 PMEMORY_AREA FirstNode
;
479 PMEMORY_AREA PreviousNode
;
481 MmVerifyMemoryAreas(AddressSpace
);
483 DPRINT("LowestAddress: %p HighestAddress: %p\n",
484 LowestAddress
, HighestAddress
);
486 AlignedAddress
= MM_ROUND_UP(LowestAddress
, Granularity
);
488 /* Special case for empty tree. */
489 if (AddressSpace
->MemoryAreaRoot
== NULL
)
491 if ((ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
493 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
494 return AlignedAddress
;
496 DPRINT("MmFindGapBottomUp: 0\n");
500 /* Go to the node with lowest address in the tree. */
501 FirstNode
= Node
= MmIterateFirstNode(AddressSpace
->MemoryAreaRoot
);
503 /* Traverse the tree from left to right. */
507 Node
= MmIterateNextNode(Node
);
511 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
512 if (Node
->StartingAddress
> AlignedAddress
&&
513 (ULONG_PTR
)Node
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
515 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
516 return AlignedAddress
;
522 /* Check if there is enough space after the last memory area. */
523 AlignedAddress
= MM_ROUND_UP(PreviousNode
->EndingAddress
, Granularity
);
524 if ((ULONG_PTR
)HighestAddress
> (ULONG_PTR
)AlignedAddress
&&
525 (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
527 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
528 return AlignedAddress
;
531 /* Check if there is enough space before the first memory area. */
532 AlignedAddress
= MM_ROUND_UP(LowestAddress
, Granularity
);
533 if (FirstNode
->StartingAddress
> AlignedAddress
&&
534 (ULONG_PTR
)FirstNode
->StartingAddress
- (ULONG_PTR
)AlignedAddress
>= Length
)
536 DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress
);
537 return AlignedAddress
;
540 DPRINT("MmFindGapBottomUp: 0\n");
547 PMADDRESS_SPACE AddressSpace
,
549 ULONG_PTR Granularity
)
551 PVOID LowestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ? MM_LOWEST_USER_ADDRESS
: MmSystemRangeStart
;
552 PVOID HighestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ?
553 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
554 PVOID AlignedAddress
;
556 PMEMORY_AREA PreviousNode
;
558 MmVerifyMemoryAreas(AddressSpace
);
560 DPRINT("LowestAddress: %p HighestAddress: %p\n",
561 LowestAddress
, HighestAddress
);
563 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)HighestAddress
- Length
+ 1, Granularity
);
565 /* Check for overflow. */
566 if (AlignedAddress
> HighestAddress
)
569 /* Special case for empty tree. */
570 if (AddressSpace
->MemoryAreaRoot
== NULL
)
572 if (AlignedAddress
>= LowestAddress
)
574 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
575 return AlignedAddress
;
577 DPRINT("MmFindGapTopDown: 0\n");
581 /* Go to the node with highest address in the tree. */
582 Node
= MmIterateLastNode(AddressSpace
->MemoryAreaRoot
);
584 /* Check if there is enough space after the last memory area. */
585 if (Node
->EndingAddress
<= AlignedAddress
)
587 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
588 return AlignedAddress
;
591 /* Traverse the tree from left to right. */
595 Node
= MmIteratePrevNode(Node
);
599 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
601 /* Check for overflow. */
602 if (AlignedAddress
> PreviousNode
->StartingAddress
)
605 if (Node
->EndingAddress
<= AlignedAddress
)
607 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
608 return AlignedAddress
;
614 AlignedAddress
= MM_ROUND_DOWN((ULONG_PTR
)PreviousNode
->StartingAddress
- Length
+ 1, Granularity
);
616 /* Check for overflow. */
617 if (AlignedAddress
> PreviousNode
->StartingAddress
)
620 if (AlignedAddress
>= LowestAddress
)
622 DPRINT("MmFindGapTopDown: %p\n", AlignedAddress
);
623 return AlignedAddress
;
626 DPRINT("MmFindGapTopDown: 0\n");
633 PMADDRESS_SPACE AddressSpace
,
635 ULONG_PTR Granularity
,
639 return MmFindGapTopDown(AddressSpace
, Length
, Granularity
);
641 return MmFindGapBottomUp(AddressSpace
, Length
, Granularity
);
646 PMADDRESS_SPACE AddressSpace
,
649 PMEMORY_AREA Node
= AddressSpace
->MemoryAreaRoot
;
650 PMEMORY_AREA RightNeighbour
= NULL
;
651 PVOID LowestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ? MM_LOWEST_USER_ADDRESS
: MmSystemRangeStart
;
652 PVOID HighestAddress
= MmGetAddressSpaceOwner(AddressSpace
) ?
653 (PVOID
)((ULONG_PTR
)MmSystemRangeStart
- 1) : (PVOID
)MAXULONG_PTR
;
655 MmVerifyMemoryAreas(AddressSpace
);
657 Address
= MM_ROUND_DOWN(Address
, PAGE_SIZE
);
659 if (LowestAddress
< MmSystemRangeStart
)
661 if (Address
>= MmSystemRangeStart
)
668 if (Address
< LowestAddress
)
676 if (Address
< Node
->StartingAddress
)
678 RightNeighbour
= Node
;
679 Node
= Node
->LeftChild
;
681 else if (Address
>= Node
->EndingAddress
)
683 Node
= Node
->RightChild
;
687 DPRINT("MmFindGapAtAddress: 0\n");
694 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
695 (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
);
696 return (ULONG_PTR
)RightNeighbour
->StartingAddress
- (ULONG_PTR
)Address
;
700 DPRINT("MmFindGapAtAddress: %p [%p]\n", Address
,
701 (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
);
702 return (ULONG_PTR
)HighestAddress
- (ULONG_PTR
)Address
;
707 * @name MmInitMemoryAreas
709 * Initialize the memory area list implementation.
715 MmInitMemoryAreas(VOID
)
717 DPRINT("MmInitMemoryAreas()\n");
718 return(STATUS_SUCCESS
);
723 * @name MmFreeMemoryArea
725 * Free an existing memory area.
727 * @param AddressSpace
728 * Address space to free the area from.
730 * Memory area we're about to free.
732 * Callback function for each freed page.
733 * @param FreePageContext
734 * Context passed to the callback function.
738 * @remarks Lock the address space before calling this function.
743 PMADDRESS_SPACE AddressSpace
,
744 PMEMORY_AREA MemoryArea
,
745 PMM_FREE_PAGE_FUNC FreePage
,
746 PVOID FreePageContext
)
748 PMEMORY_AREA
*ParentReplace
;
751 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
752 PEPROCESS Process
= MmGetAddressSpaceOwner(AddressSpace
);
754 if (Process
!= NULL
&&
755 Process
!= CurrentProcess
)
757 KeAttachProcess(&Process
->Pcb
);
760 EndAddress
= MM_ROUND_UP(MemoryArea
->EndingAddress
, PAGE_SIZE
);
761 for (Address
= (ULONG_PTR
)MemoryArea
->StartingAddress
;
762 Address
< (ULONG_PTR
)EndAddress
;
763 Address
+= PAGE_SIZE
)
765 if (MemoryArea
->Type
== MEMORY_AREA_IO_MAPPING
)
767 MmRawDeleteVirtualMapping((PVOID
)Address
);
771 BOOLEAN Dirty
= FALSE
;
772 SWAPENTRY SwapEntry
= 0;
775 if (MmIsPageSwapEntry(Process
, (PVOID
)Address
))
777 MmDeletePageFileMapping(Process
, (PVOID
)Address
, &SwapEntry
);
781 MmDeleteVirtualMapping(Process
, (PVOID
)Address
, FALSE
, &Dirty
, &Page
);
783 if (FreePage
!= NULL
)
785 FreePage(FreePageContext
, MemoryArea
, (PVOID
)Address
,
786 Page
, SwapEntry
, (BOOLEAN
)Dirty
);
791 if (Process
!= NULL
&&
792 Process
!= CurrentProcess
)
797 /* Remove the tree item. */
799 if (MemoryArea
->Parent
!= NULL
)
801 if (MemoryArea
->Parent
->LeftChild
== MemoryArea
)
802 ParentReplace
= &MemoryArea
->Parent
->LeftChild
;
804 ParentReplace
= &MemoryArea
->Parent
->RightChild
;
807 ParentReplace
= &AddressSpace
->MemoryAreaRoot
;
809 if (MemoryArea
->RightChild
== NULL
)
811 *ParentReplace
= MemoryArea
->LeftChild
;
812 if (MemoryArea
->LeftChild
)
813 MemoryArea
->LeftChild
->Parent
= MemoryArea
->Parent
;
817 if (MemoryArea
->RightChild
->LeftChild
== NULL
)
819 MemoryArea
->RightChild
->LeftChild
= MemoryArea
->LeftChild
;
820 if (MemoryArea
->LeftChild
)
821 MemoryArea
->LeftChild
->Parent
= MemoryArea
->RightChild
;
823 *ParentReplace
= MemoryArea
->RightChild
;
824 MemoryArea
->RightChild
->Parent
= MemoryArea
->Parent
;
828 PMEMORY_AREA LowestNode
;
830 LowestNode
= MemoryArea
->RightChild
->LeftChild
;
831 while (LowestNode
->LeftChild
!= NULL
)
832 LowestNode
= LowestNode
->LeftChild
;
834 LowestNode
->Parent
->LeftChild
= LowestNode
->RightChild
;
835 if (LowestNode
->RightChild
)
836 LowestNode
->RightChild
->Parent
= LowestNode
->Parent
;
838 LowestNode
->LeftChild
= MemoryArea
->LeftChild
;
839 if (MemoryArea
->LeftChild
)
840 MemoryArea
->LeftChild
->Parent
= LowestNode
;
842 LowestNode
->RightChild
= MemoryArea
->RightChild
;
843 MemoryArea
->RightChild
->Parent
= LowestNode
;
845 *ParentReplace
= LowestNode
;
846 LowestNode
->Parent
= MemoryArea
->Parent
;
851 ExFreePoolWithTag(MemoryArea
, TAG_MAREA
);
853 DPRINT("MmFreeMemoryAreaByNode() succeeded\n");
855 return STATUS_SUCCESS
;
859 * @name MmFreeMemoryAreaByPtr
861 * Free an existing memory area given a pointer inside it.
863 * @param AddressSpace
864 * Address space to free the area from.
866 * Address in the memory area we're about to free.
868 * Callback function for each freed page.
869 * @param FreePageContext
870 * Context passed to the callback function.
874 * @see MmFreeMemoryArea
876 * @todo Should we require the BaseAddress to be really the starting
877 * address of the memory area or is the current relaxed check
878 * (BaseAddress can point anywhere in the memory area) acceptable?
880 * @remarks Lock the address space before calling this function.
884 MmFreeMemoryAreaByPtr(
885 PMADDRESS_SPACE AddressSpace
,
887 PMM_FREE_PAGE_FUNC FreePage
,
888 PVOID FreePageContext
)
890 PMEMORY_AREA MemoryArea
;
892 DPRINT("MmFreeMemoryArea(AddressSpace %p, BaseAddress %p, "
893 "FreePageContext %p)\n", AddressSpace
, BaseAddress
,
896 MmVerifyMemoryAreas(AddressSpace
);
898 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
,
900 if (MemoryArea
== NULL
)
903 return(STATUS_UNSUCCESSFUL
);
906 return MmFreeMemoryArea(AddressSpace
, MemoryArea
, FreePage
, FreePageContext
);
910 * @name MmCreateMemoryArea
912 * Create a memory area.
914 * @param AddressSpace
915 * Address space to create the area in.
917 * Type of the memory area.
919 * Base address for the memory area we're about the create. On
920 * input it contains either 0 (auto-assign address) or preferred
921 * address. On output it contains the starting address of the
922 * newly created area.
924 * Length of the area to allocate.
926 * Protection attributes for the memory area.
928 * Receives a pointer to the memory area on successful exit.
932 * @remarks Lock the address space before calling this function.
936 MmCreateMemoryArea(PMADDRESS_SPACE AddressSpace
,
941 PMEMORY_AREA
*Result
,
942 BOOLEAN FixedAddress
,
943 ULONG AllocationFlags
,
944 PHYSICAL_ADDRESS BoundaryAddressMultiple
)
949 PMEMORY_AREA MemoryArea
;
951 DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
952 "*BaseAddress %p, Length %p, AllocationFlags %x, "
953 "FixedAddress %x, Result %p)\n",
954 Type
, BaseAddress
, *BaseAddress
, Length
, AllocationFlags
,
955 FixedAddress
, Result
);
957 MmVerifyMemoryAreas(AddressSpace
);
959 Granularity
= (MEMORY_AREA_VIRTUAL_MEMORY
== Type
? MM_VIRTMEM_GRANULARITY
: PAGE_SIZE
);
960 if ((*BaseAddress
) == 0 && !FixedAddress
)
962 tmpLength
= PAGE_ROUND_UP(Length
);
963 *BaseAddress
= MmFindGap(AddressSpace
,
966 (AllocationFlags
& MEM_TOP_DOWN
) == MEM_TOP_DOWN
);
967 if ((*BaseAddress
) == 0)
969 DPRINT("No suitable gap\n");
970 return STATUS_NO_MEMORY
;
975 tmpLength
= Length
+ ((ULONG_PTR
) *BaseAddress
976 - (ULONG_PTR
) MM_ROUND_DOWN(*BaseAddress
, Granularity
));
977 *BaseAddress
= MM_ROUND_DOWN(*BaseAddress
, Granularity
);
979 if (!MmGetAddressSpaceOwner(AddressSpace
) && *BaseAddress
< MmSystemRangeStart
)
982 return STATUS_ACCESS_VIOLATION
;
985 if (MmGetAddressSpaceOwner(AddressSpace
) &&
986 (ULONG_PTR
)(*BaseAddress
) + tmpLength
> (ULONG_PTR
)MmSystemRangeStart
)
989 return STATUS_ACCESS_VIOLATION
;
992 if (BoundaryAddressMultiple
.QuadPart
!= 0)
994 EndAddress
= ((char*)(*BaseAddress
)) + tmpLength
-1;
995 ASSERT(((ULONG_PTR
)*BaseAddress
/BoundaryAddressMultiple
.QuadPart
) == ((DWORD_PTR
)EndAddress
/BoundaryAddressMultiple
.QuadPart
));
998 if (MmLocateMemoryAreaByRegion(AddressSpace
,
1002 DPRINT("Memory area already occupied\n");
1003 return STATUS_CONFLICTING_ADDRESSES
;
1007 MemoryArea
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(MEMORY_AREA
),
1009 RtlZeroMemory(MemoryArea
, sizeof(MEMORY_AREA
));
1010 MemoryArea
->Type
= Type
;
1011 MemoryArea
->StartingAddress
= *BaseAddress
;
1012 MemoryArea
->EndingAddress
= (PVOID
)((ULONG_PTR
)*BaseAddress
+ tmpLength
);
1013 MemoryArea
->Protect
= Protect
;
1014 MemoryArea
->Flags
= AllocationFlags
;
1015 //MemoryArea->LockCount = 0;
1016 MemoryArea
->PageOpCount
= 0;
1017 MemoryArea
->DeleteInProgress
= FALSE
;
1019 MmInsertMemoryArea(AddressSpace
, MemoryArea
);
1021 *Result
= MemoryArea
;
1023 DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress
);
1024 return STATUS_SUCCESS
;
1028 MmMapMemoryArea(PVOID BaseAddress
,
1036 for (i
= 0; i
< PAGE_ROUND_UP(Length
) / PAGE_SIZE
; i
++)
1040 Status
= MmRequestPageMemoryConsumer(Consumer
, TRUE
, &Page
);
1041 if (!NT_SUCCESS(Status
))
1043 DPRINT1("Unable to allocate page\n");
1046 Status
= MmCreateVirtualMapping (NULL
,
1047 (PVOID
)((ULONG_PTR
)BaseAddress
+ (i
* PAGE_SIZE
)),
1051 if (!NT_SUCCESS(Status
))
1053 DPRINT1("Unable to create virtual mapping\n");
1061 MmReleaseMemoryAreaIfDecommitted(PEPROCESS Process
,
1062 PMADDRESS_SPACE AddressSpace
,
1065 PMEMORY_AREA MemoryArea
;
1070 MmVerifyMemoryAreas(AddressSpace
);
1072 MemoryArea
= MmLocateMemoryAreaByAddress(AddressSpace
, BaseAddress
);
1073 if (MemoryArea
!= NULL
)
1075 Entry
= MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
.Flink
;
1077 while (Reserved
&& Entry
!= &MemoryArea
->Data
.VirtualMemoryData
.RegionListHead
)
1079 Region
= CONTAINING_RECORD(Entry
, MM_REGION
, RegionListEntry
);
1080 Reserved
= (MEM_RESERVE
== Region
->Type
);
1081 Entry
= Entry
->Flink
;
1086 MmFreeVirtualMemory(Process
, MemoryArea
);