X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=ntoskrnl%2Fmm%2Fmarea.c;h=1dc4d612d45283155c02cf4703a8f60c0f921cef;hp=9ecaeb9188368148c9a402ddd74c490ac50c6913;hb=da5949280c3c97449ebf0776936d62a58e5ed7a0;hpb=2d18c1a929c412ffebc7e49d3934f35c0fd862da diff --git a/ntoskrnl/mm/marea.c b/ntoskrnl/mm/marea.c index 9ecaeb91883..1dc4d612d45 100644 --- a/ntoskrnl/mm/marea.c +++ b/ntoskrnl/mm/marea.c @@ -43,7 +43,7 @@ #include #define NDEBUG -#include "../cache/section/newmm.h" +#include #include #include "ARM3/miarm.h" @@ -51,313 +51,109 @@ MEMORY_AREA MiStaticMemoryAreas[MI_STATIC_MEMORY_AREAS]; ULONG MiStaticMemoryAreaCount; -/* FUNCTIONS *****************************************************************/ - -/** - * @name MmIterateFirstNode - * - * @param Node - * Head node of the MEMORY_AREA tree. - * - * @return The leftmost MEMORY_AREA node (ie. the one with lowest - * address) - */ - -static PMEMORY_AREA MmIterateFirstNode(PMEMORY_AREA Node) -{ - while (Node->LeftChild != NULL) - Node = Node->LeftChild; - - return Node; -} - -/** - * @name MmIterateNextNode - * - * @param Node - * Current node in the tree. - * - * @return Next node in the tree (sorted by address). - */ - -static PMEMORY_AREA MmIterateNextNode(PMEMORY_AREA Node) -{ - if (Node->RightChild != NULL) - { - Node = Node->RightChild; - while (Node->LeftChild != NULL) - Node = Node->LeftChild; - } - else - { - PMEMORY_AREA TempNode = NULL; - - do - { - /* Check if we're at the end of tree. */ - if (Node->Parent == NULL) - return NULL; - - TempNode = Node; - Node = Node->Parent; - } - while (TempNode == Node->RightChild); - } - return Node; -} - -/** - * @name MmIterateLastNode - * - * @param Node - * Head node of the MEMORY_AREA tree. - * - * @return The rightmost MEMORY_AREA node (ie. the one with highest - * address) - */ - -static PMEMORY_AREA MmIterateLastNode(PMEMORY_AREA Node) -{ - while (Node->RightChild != NULL) - Node = Node->RightChild; - - return Node; -} +MM_AVL_TABLE MiRosKernelVadRoot; +BOOLEAN MiRosKernelVadRootInitialized; -/** - * @name MmIteratePreviousNode - * - * @param Node - * Current node in the tree. - * - * @return Previous node in the tree (sorted by address). - */ - -static PMEMORY_AREA MmIteratePrevNode(PMEMORY_AREA Node) -{ - if (Node->LeftChild != NULL) - { - Node = Node->LeftChild; - while (Node->RightChild != NULL) - Node = Node->RightChild; - } - else - { - PMEMORY_AREA TempNode = NULL; - - do - { - /* Check if we're at the end of tree. */ - if (Node->Parent == NULL) - return NULL; - - TempNode = Node; - Node = Node->Parent; - } - while (TempNode == Node->LeftChild); - } - return Node; -} +/* FUNCTIONS *****************************************************************/ PMEMORY_AREA NTAPI MmLocateMemoryAreaByAddress( - PMMSUPPORT AddressSpace, - PVOID Address) + PMMSUPPORT AddressSpace, + PVOID Address_) { - PMEMORY_AREA Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; - - DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n", - AddressSpace, Address); - - while (Node != NULL) - { - if (Address < Node->StartingAddress) - Node = Node->LeftChild; - else if (Address >= Node->EndingAddress) - Node = Node->RightChild; - else - { - DPRINT("MmLocateMemoryAreaByAddress(%p): %p [%p - %p]\n", - Address, Node, Node->StartingAddress, Node->EndingAddress); - return Node; - } - } - - DPRINT("MmLocateMemoryAreaByAddress(%p): 0\n", Address); - return NULL; -} + ULONG_PTR StartVpn = (ULONG_PTR)Address_ / PAGE_SIZE; + PEPROCESS Process; + PMM_AVL_TABLE Table; + PMMADDRESS_NODE Node; + PMEMORY_AREA MemoryArea; + TABLE_SEARCH_RESULT Result; + PMMVAD_LONG Vad; + + Process = MmGetAddressSpaceOwner(AddressSpace); + Table = (Process != NULL) ? &Process->VadRoot : &MiRosKernelVadRoot; + + Result = MiCheckForConflictingNode(StartVpn, StartVpn, Table, &Node); + if (Result != TableFoundNode) + { + return NULL; + } -PMEMORY_AREA NTAPI -MmLocateMemoryAreaByRegion( - PMMSUPPORT AddressSpace, - PVOID Address, - ULONG_PTR Length) -{ - PMEMORY_AREA Node; - PVOID Extent = (PVOID)((ULONG_PTR)Address + Length); - - /* Special case for empty tree. */ - if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL) - return NULL; - - /* Traverse the tree from left to right. */ - for (Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink); - Node != NULL; - Node = MmIterateNextNode(Node)) - { - if (Node->StartingAddress >= Address && - Node->StartingAddress < Extent) - { - DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n", - Address, (ULONG_PTR)Address + Length, Node->StartingAddress, - Node->EndingAddress); - return Node; - } - if (Node->EndingAddress > Address && - Node->EndingAddress < Extent) - { - DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n", - Address, (ULONG_PTR)Address + Length, Node->StartingAddress, - Node->EndingAddress); - return Node; - } - if (Node->StartingAddress <= Address && - Node->EndingAddress >= Extent) - { - DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n", - Address, (ULONG_PTR)Address + Length, Node->StartingAddress, - Node->EndingAddress); - return Node; - } - if (Node->StartingAddress >= Extent) - { - DPRINT("Finished MmLocateMemoryAreaByRegion() = NULL\n"); - return NULL; - } - } - - return NULL; -} + Vad = (PMMVAD_LONG)Node; + if (Vad->u.VadFlags.Spare == 0) + { + /* Check if this is VM VAD */ + if (Vad->ControlArea == NULL) + { + /* We store the reactos MEMORY_AREA here */ + MemoryArea = (PMEMORY_AREA)Vad->FirstPrototypePte; + } + else + { + /* This is a section VAD. Store the MAREA here for now */ + MemoryArea = (PMEMORY_AREA)Vad->u4.Banked; + } + } + else + { + MemoryArea = (PMEMORY_AREA)Node; + } -/** - * @name MmCompressHelper - * - * This is helper of MmRebalanceTree. Performs a compression transformation - * count times, starting at root. - */ + return MemoryArea; +} -static VOID -MmCompressHelper( - PMMSUPPORT AddressSpace, - ULONG Count) +PMEMORY_AREA +NTAPI +MmLocateMemoryAreaByRegion( + PMMSUPPORT AddressSpace, + PVOID Address_, + ULONG_PTR Length) { - PMEMORY_AREA Root = NULL; - PMEMORY_AREA Red = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; - PMEMORY_AREA Black = Red->LeftChild; - - while (Count--) - { - if (Root) - Root->LeftChild = Black; - else - AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)Black; - Black->Parent = Root; - Red->LeftChild = Black->RightChild; - if (Black->RightChild) - Black->RightChild->Parent = Red; - Black->RightChild = Red; - Red->Parent = Black; - Root = Black; - - if (Count) - { - Red = Root->LeftChild; - Black = Red->LeftChild; - } - } -} + ULONG_PTR StartVpn = (ULONG_PTR)Address_ / PAGE_SIZE; + ULONG_PTR EndVpn = ((ULONG_PTR)Address_ + Length - 1) / PAGE_SIZE; + PEPROCESS Process; + PMM_AVL_TABLE Table; + PMMADDRESS_NODE Node; + PMEMORY_AREA MemoryArea; + TABLE_SEARCH_RESULT Result; + PMMVAD_LONG Vad; + + Process = MmGetAddressSpaceOwner(AddressSpace); + Table = (Process != NULL) ? &Process->VadRoot : &MiRosKernelVadRoot; + + Result = MiCheckForConflictingNode(StartVpn, EndVpn, Table, &Node); + if (Result != TableFoundNode) + { + return NULL; + } -/** - * @name MmRebalanceTree - * - * Rebalance a memory area tree using the Tree->Vine->Balanced Tree - * method described in libavl documentation in chapter 4.12. - * (http://www.stanford.edu/~blp/avl/libavl.html/) - */ + Vad = (PMMVAD_LONG)Node; + if (Vad->u.VadFlags.Spare == 0) + { + /* Check if this is VM VAD */ + if (Vad->ControlArea == NULL) + { + /* We store the reactos MEMORY_AREA here */ + MemoryArea = (PMEMORY_AREA)Vad->FirstPrototypePte; + } + else + { + /* This is a section VAD. Store the MAREA here for now */ + MemoryArea = (PMEMORY_AREA)Vad->u4.Banked; + } + } + else + { + MemoryArea = (PMEMORY_AREA)Node; + } -static VOID -MmRebalanceTree( - PMMSUPPORT AddressSpace) -{ - PMEMORY_AREA PreviousNode; - PMEMORY_AREA CurrentNode; - PMEMORY_AREA TempNode; - ULONG NodeCount = 0; - ULONG Vine; /* Number of nodes in main vine. */ - ULONG Leaves; /* Nodes in incomplete bottom level, if any. */ - INT Height; /* Height of produced balanced tree. */ - - /* Transform the tree into Vine. */ - - PreviousNode = NULL; - CurrentNode = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; - while (CurrentNode != NULL) - { - if (CurrentNode->RightChild == NULL) - { - PreviousNode = CurrentNode; - CurrentNode = CurrentNode->LeftChild; - NodeCount++; - } - else - { - TempNode = CurrentNode->RightChild; - - CurrentNode->RightChild = TempNode->LeftChild; - if (TempNode->LeftChild) - TempNode->LeftChild->Parent = CurrentNode; - - TempNode->LeftChild = CurrentNode; - CurrentNode->Parent = TempNode; - - CurrentNode = TempNode; - - if (PreviousNode != NULL) - PreviousNode->LeftChild = TempNode; - else - AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)TempNode; - TempNode->Parent = PreviousNode; - } - } - - /* Transform Vine back into a balanced tree. */ - - Leaves = NodeCount + 1; - for (;;) - { - ULONG Next = Leaves & (Leaves - 1); - if (Next == 0) - break; - Leaves = Next; - } - Leaves = NodeCount + 1 - Leaves; - - MmCompressHelper(AddressSpace, Leaves); - - Vine = NodeCount - Leaves; - Height = 1 + (Leaves > 0); - while (Vine > 1) - { - MmCompressHelper(AddressSpace, Vine / 2); - Vine /= 2; - Height++; - } + ASSERT(MemoryArea != NULL); + return MemoryArea; } VOID NTAPI MiInsertVad(IN PMMVAD Vad, -IN PEPROCESS Process); + IN PMM_AVL_TABLE VadRoot); ULONG NTAPI @@ -365,316 +161,99 @@ MiMakeProtectionMask( IN ULONG Protect ); + static VOID MmInsertMemoryArea( - PMMSUPPORT AddressSpace, - PMEMORY_AREA marea) + PMMSUPPORT AddressSpace, + PMEMORY_AREA marea) { - PMEMORY_AREA Node; - PMEMORY_AREA PreviousNode; - ULONG Depth = 0; - PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); - - /* Build a lame VAD if this is a user-space allocation */ - if ((marea->EndingAddress < MmSystemRangeStart) && (marea->Type != MEMORY_AREA_OWNED_BY_ARM3)) - { - PMMVAD Vad; - - ASSERT(marea->Type == MEMORY_AREA_SECTION_VIEW || marea->Type == MEMORY_AREA_CACHE); - Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD), TAG_MVAD); - ASSERT(Vad); - RtlZeroMemory(Vad, sizeof(MMVAD)); - Vad->StartingVpn = PAGE_ROUND_DOWN(marea->StartingAddress) >> PAGE_SHIFT; - /* - * For some strange reason, it is perfectly valid to create a MAREA from 0x1000 to... 0x1000. - * In a normal OS/Memory Manager, this would be retarded, but ReactOS allows this (how it works - * I don't even want to know). - */ - if (marea->EndingAddress != marea->StartingAddress) - { - Vad->EndingVpn = PAGE_ROUND_DOWN((ULONG_PTR)marea->EndingAddress - 1) >> PAGE_SHIFT; - } - else - { - Vad->EndingVpn = Vad->StartingVpn; - } - Vad->u.VadFlags.Spare = 1; - Vad->u.VadFlags.PrivateMemory = 1; - Vad->u.VadFlags.Protection = MiMakeProtectionMask(marea->Protect); - - /* Insert the VAD */ - MiInsertVad(Vad, Process); - marea->Vad = Vad; - } - else - { - marea->Vad = NULL; - } - - if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL) - { - AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)marea; - marea->LeftChild = marea->RightChild = marea->Parent = NULL; - return; - } - - Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; - do - { - DPRINT("marea->EndingAddress: %p Node->StartingAddress: %p\n", - marea->EndingAddress, Node->StartingAddress); - DPRINT("marea->StartingAddress: %p Node->EndingAddress: %p\n", - marea->StartingAddress, Node->EndingAddress); - ASSERT(marea->EndingAddress <= Node->StartingAddress || - marea->StartingAddress >= Node->EndingAddress); - ASSERT(marea->StartingAddress != Node->StartingAddress); - - PreviousNode = Node; - - if (marea->StartingAddress < Node->StartingAddress) - Node = Node->LeftChild; - else - Node = Node->RightChild; - - if (Node) - { - Depth++; - if (Depth == 22) - { - MmRebalanceTree(AddressSpace); - PreviousNode = Node->Parent; - } - } - } - while (Node != NULL); - - marea->LeftChild = marea->RightChild = NULL; - marea->Parent = PreviousNode; - if (marea->StartingAddress < PreviousNode->StartingAddress) - PreviousNode->LeftChild = marea; - else - PreviousNode->RightChild = marea; -} + PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); -static PVOID -MmFindGapBottomUp( - PMMSUPPORT AddressSpace, - ULONG_PTR Length, - ULONG_PTR Granularity) -{ - ULONG_PTR LowestAddress, HighestAddress, Candidate; - PMEMORY_AREA Root, Node; + marea->VadNode.u.VadFlags.Spare = 1; + marea->VadNode.u.VadFlags.Protection = MiMakeProtectionMask(marea->Protect); - /* Get the margins of the address space */ - if (MmGetAddressSpaceOwner(AddressSpace) != NULL) + /* Build a lame VAD if this is a user-space allocation */ + if (marea->VadNode.EndingVpn + 1 < (ULONG_PTR)MmSystemRangeStart >> PAGE_SHIFT) { - LowestAddress = (ULONG_PTR)MM_LOWEST_USER_ADDRESS; - HighestAddress = (ULONG_PTR)MmHighestUserAddress; + ASSERT(Process != NULL); + if (marea->Type != MEMORY_AREA_OWNED_BY_ARM3) + { + ASSERT(marea->Type == MEMORY_AREA_SECTION_VIEW || marea->Type == MEMORY_AREA_CACHE); + + /* Insert the VAD */ + MiLockProcessWorkingSetUnsafe(PsGetCurrentProcess(), PsGetCurrentThread()); + MiInsertVad(&marea->VadNode, &Process->VadRoot); + MiUnlockProcessWorkingSetUnsafe(PsGetCurrentProcess(), PsGetCurrentThread()); + marea->Vad = &marea->VadNode; + } } else { - LowestAddress = (ULONG_PTR)MmSystemRangeStart; - HighestAddress = MAXULONG_PTR; - } - - /* Start with the lowest address */ - Candidate = LowestAddress; - - /* Check for overflow */ - if ((Candidate + Length) < Candidate) return NULL; - - /* Get the root of the address space tree */ - Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; - - /* Go to the node with lowest address in the tree. */ - Node = Root ? MmIterateFirstNode(Root) : NULL; - while (Node && ((ULONG_PTR)Node->EndingAddress < LowestAddress)) - { - Node = MmIterateNextNode(Node); - } + ASSERT(Process == NULL); - /* Traverse the tree from low to high addresses */ - while (Node && ((ULONG_PTR)Node->EndingAddress < HighestAddress)) - { - /* Check if the memory area fits before the current node */ - if ((ULONG_PTR)Node->StartingAddress >= (Candidate + Length)) + if (!MiRosKernelVadRootInitialized) { - DPRINT("MmFindGapBottomUp: %p\n", Candidate); - ASSERT(Candidate >= LowestAddress); - return (PVOID)Candidate; + MiRosKernelVadRoot.BalancedRoot.u1.Parent = &MiRosKernelVadRoot.BalancedRoot; + MiRosKernelVadRoot.Unused = 1; + MiRosKernelVadRootInitialized = TRUE; } - /* Calculate next possible adress above this node */ - Candidate = ALIGN_UP_BY((ULONG_PTR)Node->EndingAddress, Granularity); - - /* Check for overflow */ - if ((Candidate + Length) < (ULONG_PTR)Node->EndingAddress) return NULL; - - /* Go to the next higher node */ - Node = MmIterateNextNode(Node); - } - - /* Check if there is enough space after the last memory area. */ - if ((Candidate + Length) <= HighestAddress) - { - DPRINT("MmFindGapBottomUp: %p\n", Candidate); - ASSERT(Candidate >= LowestAddress); - return (PVOID)Candidate; + /* Insert the VAD */ + MiLockWorkingSet(PsGetCurrentThread(), &MmSystemCacheWs); + MiInsertVad(&marea->VadNode, &MiRosKernelVadRoot); + MiUnlockWorkingSet(PsGetCurrentThread(), &MmSystemCacheWs); + marea->Vad = NULL; } - - DPRINT("MmFindGapBottomUp: 0\n"); - return NULL; } - -static PVOID -MmFindGapTopDown( - PMMSUPPORT AddressSpace, - ULONG_PTR Length, - ULONG_PTR Granularity) +PVOID NTAPI +MmFindGap( + PMMSUPPORT AddressSpace, + ULONG_PTR Length, + ULONG_PTR Granularity, + BOOLEAN TopDown) { - ULONG_PTR LowestAddress, HighestAddress, Candidate; - PMEMORY_AREA Root, Node; - - /* Get the margins of the address space */ - if (MmGetAddressSpaceOwner(AddressSpace) != NULL) + PEPROCESS Process; + PMM_AVL_TABLE VadRoot; + TABLE_SEARCH_RESULT Result; + PMMADDRESS_NODE Parent; + ULONG_PTR StartingAddress, HighestAddress; + + Process = MmGetAddressSpaceOwner(AddressSpace); + VadRoot = Process ? &Process->VadRoot : &MiRosKernelVadRoot; + if (TopDown) { - LowestAddress = (ULONG_PTR)MM_LOWEST_USER_ADDRESS; - HighestAddress = (ULONG_PTR)MmHighestUserAddress; + /* Find an address top-down */ + HighestAddress = Process ? (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS : (LONG_PTR)-1; + Result = MiFindEmptyAddressRangeDownTree(Length, + HighestAddress, + Granularity, + VadRoot, + &StartingAddress, + &Parent); } else { - LowestAddress = (ULONG_PTR)MmSystemRangeStart; - HighestAddress = MAXULONG_PTR; - } - - /* Calculate the highest candidate */ - Candidate = ALIGN_DOWN_BY(HighestAddress + 1 - Length, Granularity); - - /* Check for overflow. */ - if (Candidate > HighestAddress) return NULL; - - /* Get the root of the address space tree */ - Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; - - /* Go to the node with highest address in the tree. */ - Node = Root ? MmIterateLastNode(Root) : NULL; - while (Node && ((ULONG_PTR)Node->StartingAddress > HighestAddress)) - { - Node = MmIteratePrevNode(Node); - } - - /* Traverse the tree from high to low addresses */ - while (Node && ((ULONG_PTR)Node->StartingAddress > LowestAddress)) - { - /* Check if the memory area fits after the current node */ - if ((ULONG_PTR)Node->EndingAddress <= Candidate) - { - DPRINT("MmFindGapTopDown: %p\n", Candidate); - return (PVOID)Candidate; - } - - /* Calculate next possible adress below this node */ - Candidate = ALIGN_DOWN_BY((ULONG_PTR)Node->StartingAddress - Length, - Granularity); - - /* Check for overflow. */ - if (Candidate > (ULONG_PTR)Node->StartingAddress) - return NULL; - - /* Go to the next lower node */ - Node = MmIteratePrevNode(Node); + Result = MiFindEmptyAddressRangeInTree(Length, + Granularity, + VadRoot, + &Parent, + &StartingAddress); } - /* Check if the last candidate is inside the given range */ - if (Candidate >= LowestAddress) + if (Result == TableFoundNode) { - DPRINT("MmFindGapTopDown: %p\n", Candidate); - return (PVOID)Candidate; + return NULL; } - DPRINT("MmFindGapTopDown: 0\n"); - return NULL; -} - - -PVOID NTAPI -MmFindGap( - PMMSUPPORT AddressSpace, - ULONG_PTR Length, - ULONG_PTR Granularity, - BOOLEAN TopDown) -{ - if (TopDown) - return MmFindGapTopDown(AddressSpace, Length, Granularity); - - return MmFindGapBottomUp(AddressSpace, Length, Granularity); -} - -ULONG_PTR NTAPI -MmFindGapAtAddress( - PMMSUPPORT AddressSpace, - PVOID Address) -{ - PMEMORY_AREA Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink; - PMEMORY_AREA RightNeighbour = NULL; - PVOID LowestAddress = MmGetAddressSpaceOwner(AddressSpace) ? MM_LOWEST_USER_ADDRESS : MmSystemRangeStart; - PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ? - (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR; - - Address = MM_ROUND_DOWN(Address, PAGE_SIZE); - - if (LowestAddress < MmSystemRangeStart) - { - if (Address >= MmSystemRangeStart) - { - return 0; - } - } - else - { - if (Address < LowestAddress) - { - return 0; - } - } - - while (Node != NULL) - { - if (Address < Node->StartingAddress) - { - RightNeighbour = Node; - Node = Node->LeftChild; - } - else if (Address >= Node->EndingAddress) - { - Node = Node->RightChild; - } - else - { - DPRINT("MmFindGapAtAddress: 0\n"); - return 0; - } - } - - if (RightNeighbour) - { - DPRINT("MmFindGapAtAddress: %p [%p]\n", Address, - (ULONG_PTR)RightNeighbour->StartingAddress - (ULONG_PTR)Address); - return (ULONG_PTR)RightNeighbour->StartingAddress - (ULONG_PTR)Address; - } - else - { - DPRINT("MmFindGapAtAddress: %p [%p]\n", Address, - (ULONG_PTR)HighestAddress - (ULONG_PTR)Address); - return (ULONG_PTR)HighestAddress - (ULONG_PTR)Address; - } + return (PVOID)StartingAddress; } VOID NTAPI MiRemoveNode(IN PMMADDRESS_NODE Node, -IN PMM_AVL_TABLE Table); + IN PMM_AVL_TABLE Table); + /** * @name MmFreeMemoryArea @@ -694,162 +273,111 @@ IN PMM_AVL_TABLE Table); * * @remarks Lock the address space before calling this function. */ -VOID -NTAPI -MiDeletePte(IN PMMPTE PointerPte, - IN PVOID VirtualAddress, - IN PEPROCESS CurrentProcess, - IN PMMPTE PrototypePte); NTSTATUS NTAPI MmFreeMemoryArea( - PMMSUPPORT AddressSpace, - PMEMORY_AREA MemoryArea, - PMM_FREE_PAGE_FUNC FreePage, - PVOID FreePageContext) + PMMSUPPORT AddressSpace, + PMEMORY_AREA MemoryArea, + PMM_FREE_PAGE_FUNC FreePage, + PVOID FreePageContext) { - PMEMORY_AREA *ParentReplace; - ULONG_PTR Address; - PVOID EndAddress; - - if (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3) - { - PEPROCESS CurrentProcess = PsGetCurrentProcess(); - PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); - - if (Process != NULL && - Process != CurrentProcess) - { - KeAttachProcess(&Process->Pcb); - } - - EndAddress = MM_ROUND_UP(MemoryArea->EndingAddress, PAGE_SIZE); - for (Address = (ULONG_PTR)MemoryArea->StartingAddress; - Address < (ULONG_PTR)EndAddress; - Address += PAGE_SIZE) - { + ULONG_PTR Address; + PVOID EndAddress; + + /* Make sure we own the address space lock! */ + ASSERT(CONTAINING_RECORD(AddressSpace, EPROCESS, Vm)->AddressCreationLock.Owner == KeGetCurrentThread()); + + /* Check magic */ + ASSERT(MemoryArea->Magic == 'erAM'); + + if (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3) + { + PEPROCESS CurrentProcess = PsGetCurrentProcess(); + PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace); + + if (Process != NULL && + Process != CurrentProcess) + { + KeAttachProcess(&Process->Pcb); + } + + EndAddress = MM_ROUND_UP(MA_GetEndingAddress(MemoryArea), PAGE_SIZE); + for (Address = MA_GetStartingAddress(MemoryArea); + Address < (ULONG_PTR)EndAddress; + Address += PAGE_SIZE) + { BOOLEAN Dirty = FALSE; SWAPENTRY SwapEntry = 0; PFN_NUMBER Page = 0; - - if (MmIsPageSwapEntry(Process, (PVOID)Address)) - { + + if (MmIsPageSwapEntry(Process, (PVOID)Address)) + { MmDeletePageFileMapping(Process, (PVOID)Address, &SwapEntry); - } - else - { - MmDeleteVirtualMapping(Process, (PVOID)Address, FALSE, &Dirty, &Page); - } - if (FreePage != NULL) - { + } + else + { + MmDeleteVirtualMapping(Process, (PVOID)Address, &Dirty, &Page); + } + if (FreePage != NULL) + { FreePage(FreePageContext, MemoryArea, (PVOID)Address, Page, SwapEntry, (BOOLEAN)Dirty); - } + } #if (_MI_PAGING_LEVELS == 2) /* Remove page table reference */ ASSERT(KeGetCurrentIrql() <= APC_LEVEL); - if((SwapEntry || Page) && ((PVOID)Address < MmSystemRangeStart)) + if ((SwapEntry || Page) && ((PVOID)Address < MmSystemRangeStart)) { ASSERT(AddressSpace != MmGetKernelAddressSpace()); - if(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] == 0) + if (MiQueryPageTableReferences((PVOID)Address) == 0) { /* No PTE relies on this PDE. Release it */ - KIRQL OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); + KIRQL OldIrql = MiAcquirePfnLock(); PMMPDE PointerPde = MiAddressToPde(Address); ASSERT(PointerPde->u.Hard.Valid == 1); MiDeletePte(PointerPde, MiPdeToPte(PointerPde), Process, NULL); ASSERT(PointerPde->u.Hard.Valid == 0); - KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); + MiReleasePfnLock(OldIrql); } } #endif - } - - if (Process != NULL && - Process != CurrentProcess) - { - KeDetachProcess(); - } - - if (MemoryArea->Vad) - { - ASSERT(MemoryArea->EndingAddress < MmSystemRangeStart); - ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW || MemoryArea->Type == MEMORY_AREA_CACHE); - - /* MmCleanProcessAddressSpace might have removed it (and this would be MmDeleteProcessAdressSpace) */ - ASSERT(((PMMVAD)MemoryArea->Vad)->u.VadFlags.Spare != 0); - if (((PMMVAD)MemoryArea->Vad)->u.VadFlags.Spare == 1) - { - MiRemoveNode(MemoryArea->Vad, &Process->VadRoot); - } - - ExFreePoolWithTag(MemoryArea->Vad, TAG_MVAD); - MemoryArea->Vad = NULL; - } + } + + if (Process != NULL && + Process != CurrentProcess) + { + KeDetachProcess(); + } + + //if (MemoryArea->VadNode.StartingVpn < (ULONG_PTR)MmSystemRangeStart >> PAGE_SHIFT + if (MemoryArea->Vad) + { + ASSERT(MemoryArea->VadNode.EndingVpn + 1 < (ULONG_PTR)MmSystemRangeStart >> PAGE_SHIFT); + ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW || MemoryArea->Type == MEMORY_AREA_CACHE); + + /* MmCleanProcessAddressSpace might have removed it (and this would be MmDeleteProcessAdressSpace) */ + ASSERT(MemoryArea->VadNode.u.VadFlags.Spare != 0); + if (((PMMVAD)MemoryArea->Vad)->u.VadFlags.Spare == 1) + { + MiRemoveNode((PMMADDRESS_NODE)&MemoryArea->VadNode, &Process->VadRoot); + } + + MemoryArea->Vad = NULL; + } + else + { + MiRemoveNode((PMMADDRESS_NODE)&MemoryArea->VadNode, &MiRosKernelVadRoot); + } } - /* There must be no page ops in progress */ - ASSERT(MemoryArea->PageOpCount == 0); - - /* Remove the tree item. */ - { - if (MemoryArea->Parent != NULL) - { - if (MemoryArea->Parent->LeftChild == MemoryArea) - ParentReplace = &MemoryArea->Parent->LeftChild; - else - ParentReplace = &MemoryArea->Parent->RightChild; - } - else - ParentReplace = (PMEMORY_AREA*)&AddressSpace->WorkingSetExpansionLinks.Flink; - - if (MemoryArea->RightChild == NULL) - { - *ParentReplace = MemoryArea->LeftChild; - if (MemoryArea->LeftChild) - MemoryArea->LeftChild->Parent = MemoryArea->Parent; - } - else - { - if (MemoryArea->RightChild->LeftChild == NULL) - { - MemoryArea->RightChild->LeftChild = MemoryArea->LeftChild; - if (MemoryArea->LeftChild) - MemoryArea->LeftChild->Parent = MemoryArea->RightChild; - - *ParentReplace = MemoryArea->RightChild; - MemoryArea->RightChild->Parent = MemoryArea->Parent; - } - else - { - PMEMORY_AREA LowestNode; - - LowestNode = MemoryArea->RightChild->LeftChild; - while (LowestNode->LeftChild != NULL) - LowestNode = LowestNode->LeftChild; - - LowestNode->Parent->LeftChild = LowestNode->RightChild; - if (LowestNode->RightChild) - LowestNode->RightChild->Parent = LowestNode->Parent; - - LowestNode->LeftChild = MemoryArea->LeftChild; - if (MemoryArea->LeftChild) - MemoryArea->LeftChild->Parent = LowestNode; - - LowestNode->RightChild = MemoryArea->RightChild; - MemoryArea->RightChild->Parent = LowestNode; - - *ParentReplace = LowestNode; - LowestNode->Parent = MemoryArea->Parent; - } - } - } - - ExFreePoolWithTag(MemoryArea, TAG_MAREA); - - DPRINT("MmFreeMemoryAreaByNode() succeeded\n"); - - return STATUS_SUCCESS; +#if DBG + MemoryArea->Magic = 'daeD'; +#endif + ExFreePoolWithTag(MemoryArea, TAG_MAREA); + + DPRINT("MmFreeMemoryAreaByNode() succeeded\n"); + + return STATUS_SUCCESS; } /** @@ -885,143 +413,153 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace, ULONG_PTR Length, ULONG Protect, PMEMORY_AREA *Result, - BOOLEAN FixedAddress, ULONG AllocationFlags, - PHYSICAL_ADDRESS BoundaryAddressMultiple) + ULONG Granularity) { - PVOID EndAddress; - ULONG Granularity; - ULONG_PTR tmpLength; - PMEMORY_AREA MemoryArea; - - DPRINT("MmCreateMemoryArea(Type 0x%lx, BaseAddress %p, " - "*BaseAddress %p, Length %p, AllocationFlags %x, " - "FixedAddress %x, Result %p)\n", - Type, BaseAddress, *BaseAddress, Length, AllocationFlags, - FixedAddress, Result); - - Granularity = PAGE_SIZE; - if ((*BaseAddress) == 0 && !FixedAddress) - { - tmpLength = (ULONG_PTR)MM_ROUND_UP(Length, Granularity); - *BaseAddress = MmFindGap(AddressSpace, - tmpLength, - Granularity, - (AllocationFlags & MEM_TOP_DOWN) == MEM_TOP_DOWN); - if ((*BaseAddress) == 0) - { - DPRINT("No suitable gap\n"); - return STATUS_NO_MEMORY; - } - } - else - { - tmpLength = Length + ((ULONG_PTR) *BaseAddress - - (ULONG_PTR) MM_ROUND_DOWN(*BaseAddress, Granularity)); - tmpLength = (ULONG_PTR)MM_ROUND_UP(tmpLength, Granularity); - *BaseAddress = MM_ROUND_DOWN(*BaseAddress, Granularity); - - if (!MmGetAddressSpaceOwner(AddressSpace) && *BaseAddress < MmSystemRangeStart) - { - return STATUS_ACCESS_VIOLATION; - } - - if (MmGetAddressSpaceOwner(AddressSpace) && - (ULONG_PTR)(*BaseAddress) + tmpLength > (ULONG_PTR)MmSystemRangeStart) - { - DPRINT("Memory area for user mode address space exceeds MmSystemRangeStart\n"); - return STATUS_ACCESS_VIOLATION; - } - - if (BoundaryAddressMultiple.QuadPart != 0) - { - EndAddress = ((char*)(*BaseAddress)) + tmpLength-1; - ASSERT(((ULONG_PTR)*BaseAddress/BoundaryAddressMultiple.QuadPart) == ((DWORD_PTR)EndAddress/BoundaryAddressMultiple.QuadPart)); - } - - if (MmLocateMemoryAreaByRegion(AddressSpace, - *BaseAddress, - tmpLength) != NULL) - { - DPRINT("Memory area already occupied\n"); - return STATUS_CONFLICTING_ADDRESSES; - } - } - - // - // Is this a static memory area? - // + ULONG_PTR tmpLength; + PMEMORY_AREA MemoryArea; + ULONG_PTR EndingAddress; + + DPRINT("MmCreateMemoryArea(Type 0x%lx, BaseAddress %p, " + "*BaseAddress %p, Length %p, AllocationFlags %x, " + "Result %p)\n", + Type, BaseAddress, *BaseAddress, Length, AllocationFlags, + Result); + + /* Is this a static memory area? */ if (Type & MEMORY_AREA_STATIC) { - // - // Use the static array instead of the pool - // + /* Use the static array instead of the pool */ ASSERT(MiStaticMemoryAreaCount < MI_STATIC_MEMORY_AREAS); MemoryArea = &MiStaticMemoryAreas[MiStaticMemoryAreaCount++]; - Type &= ~MEMORY_AREA_STATIC; } else { - // - // Allocate the memory area from nonpaged pool - // + /* Allocate the memory area from nonpaged pool */ MemoryArea = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA), TAG_MAREA); } - if (!MemoryArea) return STATUS_NO_MEMORY; + if (!MemoryArea) + { + DPRINT1("Not enough memory.\n"); + return STATUS_NO_MEMORY; + } - RtlZeroMemory(MemoryArea, sizeof(MEMORY_AREA)); - MemoryArea->Type = Type; - MemoryArea->StartingAddress = *BaseAddress; - MemoryArea->EndingAddress = (PVOID)((ULONG_PTR)*BaseAddress + tmpLength); - MemoryArea->Protect = Protect; - MemoryArea->Flags = AllocationFlags; - //MemoryArea->LockCount = 0; - MemoryArea->PageOpCount = 0; - MemoryArea->DeleteInProgress = FALSE; + RtlZeroMemory(MemoryArea, sizeof(MEMORY_AREA)); + MemoryArea->Type = Type & ~MEMORY_AREA_STATIC; + MemoryArea->Protect = Protect; + MemoryArea->Flags = AllocationFlags; + MemoryArea->Magic = 'erAM'; + MemoryArea->DeleteInProgress = FALSE; - MmInsertMemoryArea(AddressSpace, MemoryArea); + if (*BaseAddress == 0) + { + tmpLength = (ULONG_PTR)MM_ROUND_UP(Length, PAGE_SIZE); + *BaseAddress = MmFindGap(AddressSpace, + tmpLength, + Granularity, + (AllocationFlags & MEM_TOP_DOWN) == MEM_TOP_DOWN); + if ((*BaseAddress) == 0) + { + DPRINT("No suitable gap\n"); + if (!(Type & MEMORY_AREA_STATIC)) ExFreePoolWithTag(MemoryArea, TAG_MAREA); + return STATUS_NO_MEMORY; + } - *Result = MemoryArea; + MemoryArea->VadNode.StartingVpn = (ULONG_PTR)*BaseAddress >> PAGE_SHIFT; + MemoryArea->VadNode.EndingVpn = ((ULONG_PTR)*BaseAddress + tmpLength - 1) >> PAGE_SHIFT; + MmInsertMemoryArea(AddressSpace, MemoryArea); + } + else + { + EndingAddress = ((ULONG_PTR)*BaseAddress + Length - 1) | (PAGE_SIZE - 1); + *BaseAddress = ALIGN_DOWN_POINTER_BY(*BaseAddress, Granularity); + tmpLength = EndingAddress + 1 - (ULONG_PTR)*BaseAddress; + + if (!MmGetAddressSpaceOwner(AddressSpace) && *BaseAddress < MmSystemRangeStart) + { + ASSERT(FALSE); + if (!(Type & MEMORY_AREA_STATIC)) ExFreePoolWithTag(MemoryArea, TAG_MAREA); + return STATUS_ACCESS_VIOLATION; + } + + if (MmGetAddressSpaceOwner(AddressSpace) && + (ULONG_PTR)(*BaseAddress) + tmpLength > (ULONG_PTR)MmSystemRangeStart) + { + DPRINT("Memory area for user mode address space exceeds MmSystemRangeStart\n"); + if (!(Type & MEMORY_AREA_STATIC)) ExFreePoolWithTag(MemoryArea, TAG_MAREA); + return STATUS_ACCESS_VIOLATION; + } - DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress); - return STATUS_SUCCESS; + /* No need to check ARM3 owned memory areas, the range MUST be free */ + if (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3) + { + if (MmLocateMemoryAreaByRegion(AddressSpace, + *BaseAddress, + tmpLength) != NULL) + { + DPRINT("Memory area already occupied\n"); + if (!(Type & MEMORY_AREA_STATIC)) ExFreePoolWithTag(MemoryArea, TAG_MAREA); + return STATUS_CONFLICTING_ADDRESSES; + } + } + + MemoryArea->VadNode.StartingVpn = (ULONG_PTR)*BaseAddress >> PAGE_SHIFT; + MemoryArea->VadNode.EndingVpn = ((ULONG_PTR)*BaseAddress + tmpLength - 1) >> PAGE_SHIFT; + MmInsertMemoryArea(AddressSpace, MemoryArea); + } + + *Result = MemoryArea; + + DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress); + return STATUS_SUCCESS; } -VOID NTAPI -MmMapMemoryArea(PVOID BaseAddress, - SIZE_T Length, - ULONG Consumer, - ULONG Protection) +VOID +NTAPI +MiRosCleanupMemoryArea( + PEPROCESS Process, + PMMVAD Vad) { - ULONG i; - NTSTATUS Status; - - ASSERT(((ULONG_PTR)BaseAddress % PAGE_SIZE) == 0); - - for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++) - { - PFN_NUMBER Page; - - Status = MmRequestPageMemoryConsumer(Consumer, TRUE, &Page); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Unable to allocate page\n"); - KeBugCheck(MEMORY_MANAGEMENT); - } - Status = MmCreateVirtualMapping (NULL, - (PVOID)((ULONG_PTR)BaseAddress + (i * PAGE_SIZE)), - Protection, - &Page, - 1); - if (!NT_SUCCESS(Status)) - { - DPRINT1("Unable to create virtual mapping\n"); - KeBugCheck(MEMORY_MANAGEMENT); - } - } + PMEMORY_AREA MemoryArea; + PVOID BaseAddress; + NTSTATUS Status; + + /* We must be called from MmCleanupAddressSpace and nowhere else! + Make sure things are as expected... */ + ASSERT(Process == PsGetCurrentProcess()); + ASSERT(Process->VmDeleted == TRUE); + ASSERT(((PsGetCurrentThread()->ThreadsProcess == Process) && + (Process->ActiveThreads == 1)) || + (Process->ActiveThreads == 0)); + + /* We are in cleanup, we don't need to synchronize */ + MmUnlockAddressSpace(&Process->Vm); + + MemoryArea = (PMEMORY_AREA)Vad; + BaseAddress = (PVOID)MA_GetStartingAddress(MemoryArea); + + if (MemoryArea->Type == MEMORY_AREA_SECTION_VIEW) + { + Status = MiRosUnmapViewOfSection(Process, BaseAddress, Process->ProcessExiting); + } + else if (MemoryArea->Type == MEMORY_AREA_CACHE) + { + Status = MmUnmapViewOfCacheSegment(&Process->Vm, BaseAddress); + } + else + { + /* There shouldn't be anything else! */ + ASSERT(FALSE); + } + + /* Make sure this worked! */ + ASSERT(NT_SUCCESS(Status)); + + /* Lock the address space again */ + MmLockAddressSpace(&Process->Vm); } VOID @@ -1032,83 +570,67 @@ NTSTATUS NTAPI MmDeleteProcessAddressSpace(PEPROCESS Process) { - PVOID Address; - PMEMORY_AREA MemoryArea; + KIRQL OldIrql; + PVOID Address; - DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process, - Process->ImageFileName); + DPRINT("MmDeleteProcessAddressSpace(Process %p (%s))\n", Process, + Process->ImageFileName); #ifndef _M_AMD64 - RemoveEntryList(&Process->MmProcessLinks); + OldIrql = MiAcquireExpansionLock(); + RemoveEntryList(&Process->MmProcessLinks); + MiReleaseExpansionLock(OldIrql); #endif - MmLockAddressSpace(&Process->Vm); - - while ((MemoryArea = (PMEMORY_AREA)Process->Vm.WorkingSetExpansionLinks.Flink) != NULL) - { - switch (MemoryArea->Type) - { - case MEMORY_AREA_SECTION_VIEW: - Address = (PVOID)MemoryArea->StartingAddress; - MmUnlockAddressSpace(&Process->Vm); - MmUnmapViewOfSection(Process, Address); - MmLockAddressSpace(&Process->Vm); - break; - - case MEMORY_AREA_CACHE: - Address = (PVOID)MemoryArea->StartingAddress; - MmUnlockAddressSpace(&Process->Vm); - MmUnmapViewOfCacheSegment(&Process->Vm, Address); - MmLockAddressSpace(&Process->Vm); - break; - - case MEMORY_AREA_OWNED_BY_ARM3: - MmFreeMemoryArea(&Process->Vm, - MemoryArea, - NULL, - NULL); - break; - - default: - KeBugCheck(MEMORY_MANAGEMENT); - } - } - + MmLockAddressSpace(&Process->Vm); + + /* There should not be any memory areas left! */ + ASSERT(Process->Vm.WorkingSetExpansionLinks.Flink == NULL); + #if (_MI_PAGING_LEVELS == 2) { KIRQL OldIrql; PMMPDE pointerPde; /* Attach to Process */ KeAttachProcess(&Process->Pcb); - + /* Acquire PFN lock */ - OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); - - for(Address = MI_LOWEST_VAD_ADDRESS; - Address < MM_HIGHEST_VAD_ADDRESS; - Address =(PVOID)((ULONG_PTR)Address + (PAGE_SIZE * PTE_COUNT))) + OldIrql = MiAcquirePfnLock(); + + for (Address = MI_LOWEST_VAD_ADDRESS; + Address < MM_HIGHEST_VAD_ADDRESS; + Address =(PVOID)((ULONG_PTR)Address + (PAGE_SIZE * PTE_COUNT))) { /* At this point all references should be dead */ - ASSERT(MmWorkingSetList->UsedPageTableEntries[MiGetPdeOffset(Address)] == 0); + if (MiQueryPageTableReferences(Address) != 0) + { + DPRINT1("Process %p, Address %p, UsedPageTableEntries %lu\n", + Process, + Address, + MiQueryPageTableReferences(Address)); + ASSERT(MiQueryPageTableReferences(Address) == 0); + } + pointerPde = MiAddressToPde(Address); /* Unlike in ARM3, we don't necesarrily free the PDE page as soon as reference reaches 0, * so we must clean up a bit when process closes */ - if(pointerPde->u.Hard.Valid) + if (pointerPde->u.Hard.Valid) MiDeletePte(pointerPde, MiPdeToPte(pointerPde), Process, NULL); ASSERT(pointerPde->u.Hard.Valid == 0); } + /* Release lock */ - KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql); - + MiReleasePfnLock(OldIrql); + /* Detach */ KeDetachProcess(); } #endif - MmUnlockAddressSpace(&Process->Vm); + MmUnlockAddressSpace(&Process->Vm); - DPRINT("Finished MmReleaseMmInfo()\n"); - MmDeleteProcessAddressSpace2(Process); - return(STATUS_SUCCESS); + DPRINT("Finished MmDeleteProcessAddressSpace()\n"); + MmDeleteProcessAddressSpace2(Process); + return(STATUS_SUCCESS); } /* EOF */