2008-03-09 14:11:42 +00:00
|
|
|
/*
|
2005-06-07 17:07:34 +00:00
|
|
|
* Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
|
|
|
|
*
|
2005-06-07 20:15:16 +00:00
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
2005-06-07 17:07:34 +00:00
|
|
|
*
|
2005-06-07 20:15:16 +00:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
2005-06-07 17:07:34 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2005-06-07 20:15:16 +00:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
2005-06-07 17:07:34 +00:00
|
|
|
*
|
2005-06-07 20:15:16 +00:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2005-06-07 17:07:34 +00:00
|
|
|
*
|
|
|
|
*
|
1998-09-05 17:33:57 +00:00
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: ntoskrnl/mm/marea.c
|
|
|
|
* PURPOSE: Implements memory areas
|
2005-05-09 01:38:29 +00:00
|
|
|
*
|
2005-06-07 17:07:34 +00:00
|
|
|
* PROGRAMMERS: Rex Jolliff
|
|
|
|
* David Welch
|
|
|
|
* Eric Kohl
|
|
|
|
* Philip Susi
|
|
|
|
* Casper Hornstrup
|
|
|
|
* Eric Kohl
|
|
|
|
* Ge van Geldorp
|
|
|
|
* Royce Mitchell III
|
2007-10-19 23:21:45 +00:00
|
|
|
* Aleksey Bragin
|
2005-06-07 17:07:34 +00:00
|
|
|
* Jason Filby
|
|
|
|
* Thomas Weidenmueller
|
|
|
|
* Gunnar Andre' Dalsnes
|
2005-06-07 20:15:16 +00:00
|
|
|
* Mike Nordell
|
2005-06-07 17:07:34 +00:00
|
|
|
* Alex Ionescu
|
|
|
|
* Filip Navara
|
|
|
|
* Herve Poussineau
|
|
|
|
* Steven Edwards
|
1998-09-05 17:33:57 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
2004-08-15 16:39:12 +00:00
|
|
|
#include <ntoskrnl.h>
|
1998-09-05 17:33:57 +00:00
|
|
|
#define NDEBUG
|
2008-08-30 16:31:06 +00:00
|
|
|
#include <debug.h>
|
1998-09-05 17:33:57 +00:00
|
|
|
|
2009-06-21 05:46:50 +00:00
|
|
|
MEMORY_AREA MiStaticMemoryAreas[MI_STATIC_MEMORY_AREAS];
|
|
|
|
ULONG MiStaticMemoryAreaCount;
|
|
|
|
|
1998-09-05 17:33:57 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
/**
|
|
|
|
* @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;
|
2005-01-29 03:15:05 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
/* Check if we're at the end of tree. */
|
|
|
|
if (Node->Parent == NULL)
|
|
|
|
return NULL;
|
2005-01-29 03:15:05 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
TempNode = Node;
|
|
|
|
Node = Node->Parent;
|
|
|
|
}
|
|
|
|
while (TempNode == Node->RightChild);
|
|
|
|
}
|
|
|
|
return Node;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-11-13 17:28:24 +00:00
|
|
|
* @name MmIterateLastNode
|
2005-01-02 17:55:06 +00:00
|
|
|
*
|
|
|
|
* @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)
|
1998-09-05 17:33:57 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
while (Node->RightChild != NULL)
|
|
|
|
Node = Node->RightChild;
|
|
|
|
|
|
|
|
return Node;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2005-11-13 17:28:24 +00:00
|
|
|
* @name MmIteratePreviousNode
|
2005-01-02 17:55:06 +00:00
|
|
|
*
|
|
|
|
* @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;
|
2005-01-29 03:15:05 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
/* Check if we're at the end of tree. */
|
|
|
|
if (Node->Parent == NULL)
|
|
|
|
return NULL;
|
2005-01-29 03:15:05 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
TempNode = Node;
|
|
|
|
Node = Node->Parent;
|
|
|
|
}
|
|
|
|
while (TempNode == Node->LeftChild);
|
|
|
|
}
|
|
|
|
return Node;
|
|
|
|
}
|
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
PMEMORY_AREA NTAPI
|
2005-01-02 19:14:52 +00:00
|
|
|
MmLocateMemoryAreaByAddress(
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
2005-01-02 17:55:06 +00:00
|
|
|
PVOID Address)
|
1998-09-05 17:33:57 +00:00
|
|
|
{
|
2009-04-27 10:12:57 +00:00
|
|
|
PMEMORY_AREA Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
|
1998-09-05 17:33:57 +00:00
|
|
|
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
|
2005-01-02 17:55:06 +00:00
|
|
|
AddressSpace, Address);
|
|
|
|
|
|
|
|
while (Node != NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
if (Address < Node->StartingAddress)
|
|
|
|
Node = Node->LeftChild;
|
|
|
|
else if (Address >= Node->EndingAddress)
|
|
|
|
Node = Node->RightChild;
|
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmLocateMemoryAreaByAddress(%p): %p [%p - %p]\n",
|
2005-01-02 17:55:06 +00:00
|
|
|
Address, Node, Node->StartingAddress, Node->EndingAddress);
|
|
|
|
return Node;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmLocateMemoryAreaByAddress(%p): 0\n", Address);
|
2005-01-02 17:55:06 +00:00
|
|
|
return NULL;
|
1998-09-05 17:33:57 +00:00
|
|
|
}
|
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
PMEMORY_AREA NTAPI
|
2005-01-02 19:14:52 +00:00
|
|
|
MmLocateMemoryAreaByRegion(
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
2005-01-02 17:55:06 +00:00
|
|
|
PVOID Address,
|
|
|
|
ULONG_PTR Length)
|
1998-09-05 17:33:57 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
PMEMORY_AREA Node;
|
|
|
|
PVOID Extent = (PVOID)((ULONG_PTR)Address + Length);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
/* Special case for empty tree. */
|
2009-04-27 10:12:57 +00:00
|
|
|
if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
|
2005-01-02 17:55:06 +00:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Traverse the tree from left to right. */
|
2009-04-27 10:12:57 +00:00
|
|
|
for (Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
|
2005-01-02 17:55:06 +00:00
|
|
|
Node != NULL;
|
|
|
|
Node = MmIterateNextNode(Node))
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
if (Node->StartingAddress >= Address &&
|
|
|
|
Node->StartingAddress < Extent)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
|
|
|
|
Address, (ULONG_PTR)Address + Length, Node->StartingAddress,
|
2005-01-02 17:55:06 +00:00
|
|
|
Node->EndingAddress);
|
|
|
|
return Node;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
if (Node->EndingAddress > Address &&
|
|
|
|
Node->EndingAddress < Extent)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
|
|
|
|
Address, (ULONG_PTR)Address + Length, Node->StartingAddress,
|
2005-01-02 17:55:06 +00:00
|
|
|
Node->EndingAddress);
|
|
|
|
return Node;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
if (Node->StartingAddress <= Address &&
|
|
|
|
Node->EndingAddress >= Extent)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmLocateMemoryAreaByRegion(%p - %p): %p - %p\n",
|
|
|
|
Address, (ULONG_PTR)Address + Length, Node->StartingAddress,
|
2005-01-02 17:55:06 +00:00
|
|
|
Node->EndingAddress);
|
|
|
|
return Node;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
if (Node->StartingAddress >= Extent)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 19:14:52 +00:00
|
|
|
DPRINT("Finished MmLocateMemoryAreaByRegion() = NULL\n");
|
2005-01-02 17:55:06 +00:00
|
|
|
return NULL;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
1998-09-05 17:33:57 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-11 22:15:41 +00:00
|
|
|
/**
|
2005-01-02 17:55:06 +00:00
|
|
|
* @name MmCompressHelper
|
|
|
|
*
|
|
|
|
* This is helper of MmRebalanceTree. Performs a compression transformation
|
2005-01-29 03:15:05 +00:00
|
|
|
* count times, starting at root.
|
2005-01-02 17:55:06 +00:00
|
|
|
*/
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
static VOID
|
|
|
|
MmCompressHelper(
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
2005-01-29 03:15:05 +00:00
|
|
|
ULONG Count)
|
2005-01-02 17:55:06 +00:00
|
|
|
{
|
|
|
|
PMEMORY_AREA Root = NULL;
|
2009-04-27 10:12:57 +00:00
|
|
|
PMEMORY_AREA Red = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
|
2005-01-02 17:55:06 +00:00
|
|
|
PMEMORY_AREA Black = Red->LeftChild;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
while (Count--)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
if (Root)
|
|
|
|
Root->LeftChild = Black;
|
|
|
|
else
|
2009-04-27 10:12:57 +00:00
|
|
|
AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)Black;
|
2005-01-02 17:55:06 +00:00
|
|
|
Black->Parent = Root;
|
|
|
|
Red->LeftChild = Black->RightChild;
|
|
|
|
if (Black->RightChild)
|
|
|
|
Black->RightChild->Parent = Red;
|
|
|
|
Black->RightChild = Red;
|
|
|
|
Red->Parent = Black;
|
|
|
|
Root = Black;
|
|
|
|
|
|
|
|
if (Count)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
Red = Root->LeftChild;
|
|
|
|
Black = Red->LeftChild;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
1998-09-05 17:33:57 +00:00
|
|
|
}
|
|
|
|
|
2005-01-11 22:15:41 +00:00
|
|
|
/**
|
2005-01-02 17:55:06 +00:00
|
|
|
* @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/)
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VOID
|
|
|
|
MmRebalanceTree(
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace)
|
1998-09-05 17:33:57 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
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;
|
2009-04-27 10:12:57 +00:00
|
|
|
CurrentNode = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
|
2005-01-02 17:55:06 +00:00
|
|
|
while (CurrentNode != NULL)
|
|
|
|
{
|
2005-01-29 03:15:05 +00:00
|
|
|
if (CurrentNode->RightChild == NULL)
|
2005-01-02 17:55:06 +00:00
|
|
|
{
|
|
|
|
PreviousNode = CurrentNode;
|
|
|
|
CurrentNode = CurrentNode->LeftChild;
|
|
|
|
NodeCount++;
|
|
|
|
}
|
2005-01-29 03:15:05 +00:00
|
|
|
else
|
2005-01-02 17:55:06 +00:00
|
|
|
{
|
|
|
|
TempNode = CurrentNode->RightChild;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
CurrentNode->RightChild = TempNode->LeftChild;
|
|
|
|
if (TempNode->LeftChild)
|
|
|
|
TempNode->LeftChild->Parent = CurrentNode;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
TempNode->LeftChild = CurrentNode;
|
|
|
|
CurrentNode->Parent = TempNode;
|
2004-09-28 19:49:21 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
CurrentNode = TempNode;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
if (PreviousNode != NULL)
|
|
|
|
PreviousNode->LeftChild = TempNode;
|
|
|
|
else
|
2009-04-27 10:12:57 +00:00
|
|
|
AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)TempNode;
|
2005-01-02 17:55:06 +00:00
|
|
|
TempNode->Parent = PreviousNode;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
/* Transform Vine back into a balanced tree. */
|
|
|
|
|
|
|
|
Leaves = NodeCount + 1;
|
2005-01-29 03:15:05 +00:00
|
|
|
for (;;)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
ULONG Next = Leaves & (Leaves - 1);
|
|
|
|
if (Next == 0)
|
|
|
|
break;
|
|
|
|
Leaves = Next;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
Leaves = NodeCount + 1 - Leaves;
|
|
|
|
|
|
|
|
MmCompressHelper(AddressSpace, Leaves);
|
|
|
|
|
|
|
|
Vine = NodeCount - Leaves;
|
|
|
|
Height = 1 + (Leaves > 0);
|
2005-01-29 03:15:05 +00:00
|
|
|
while (Vine > 1)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
MmCompressHelper(AddressSpace, Vine / 2);
|
|
|
|
Vine /= 2;
|
|
|
|
Height++;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
}
|
|
|
|
|
2010-10-05 05:07:13 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
MiInsertVad(IN PMMVAD Vad,
|
|
|
|
IN PEPROCESS Process);
|
|
|
|
|
2010-10-18 14:25:33 +00:00
|
|
|
ULONG
|
|
|
|
NTAPI
|
|
|
|
MiMakeProtectionMask(
|
|
|
|
IN ULONG Protect
|
|
|
|
);
|
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
static VOID
|
|
|
|
MmInsertMemoryArea(
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
2005-01-02 17:55:06 +00:00
|
|
|
PMEMORY_AREA marea)
|
|
|
|
{
|
|
|
|
PMEMORY_AREA Node;
|
|
|
|
PMEMORY_AREA PreviousNode;
|
|
|
|
ULONG Depth = 0;
|
|
|
|
|
2010-10-05 05:07:13 +00:00
|
|
|
/* Build a lame VAD if this is a user-space allocation */
|
|
|
|
if ((marea->EndingAddress < MmSystemRangeStart) && (marea->Type != MEMORY_AREA_OWNED_BY_ARM3))
|
|
|
|
{
|
|
|
|
ASSERT(marea->Type == MEMORY_AREA_VIRTUAL_MEMORY || marea->Type == MEMORY_AREA_SECTION_VIEW);
|
|
|
|
PMMVAD Vad;
|
|
|
|
Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD), 'Fake');
|
|
|
|
ASSERT(Vad);
|
|
|
|
RtlZeroMemory(Vad, sizeof(MMVAD));
|
|
|
|
Vad->StartingVpn = PAGE_ROUND_DOWN(marea->StartingAddress) >> PAGE_SHIFT;
|
2010-10-07 17:35:25 +00:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
2010-10-05 05:07:13 +00:00
|
|
|
Vad->u.VadFlags.Spare = 1;
|
|
|
|
Vad->u.VadFlags.PrivateMemory = 1;
|
2010-10-18 14:25:33 +00:00
|
|
|
Vad->u.VadFlags.Protection = MiMakeProtectionMask(marea->Protect);
|
2010-10-05 05:07:13 +00:00
|
|
|
MiInsertVad(Vad, MmGetAddressSpaceOwner(AddressSpace));
|
|
|
|
marea->Vad = Vad;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
marea->Vad = NULL;
|
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
|
2009-04-27 10:12:57 +00:00
|
|
|
if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2009-04-27 10:12:57 +00:00
|
|
|
AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)marea;
|
2005-01-02 17:55:06 +00:00
|
|
|
marea->LeftChild = marea->RightChild = marea->Parent = NULL;
|
|
|
|
return;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
|
2009-04-27 10:12:57 +00:00
|
|
|
Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
|
2005-01-02 17:55:06 +00:00
|
|
|
do
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("marea->EndingAddress: %p Node->StartingAddress: %p\n",
|
2005-01-02 17:55:06 +00:00
|
|
|
marea->EndingAddress, Node->StartingAddress);
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("marea->StartingAddress: %p Node->EndingAddress: %p\n",
|
2005-01-02 17:55:06 +00:00
|
|
|
marea->StartingAddress, Node->EndingAddress);
|
|
|
|
ASSERT(marea->EndingAddress <= Node->StartingAddress ||
|
|
|
|
marea->StartingAddress >= Node->EndingAddress);
|
|
|
|
ASSERT(marea->StartingAddress != Node->StartingAddress);
|
2005-01-29 03:15:05 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
PreviousNode = Node;
|
2005-01-29 03:15:05 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
if (marea->StartingAddress < Node->StartingAddress)
|
|
|
|
Node = Node->LeftChild;
|
|
|
|
else
|
|
|
|
Node = Node->RightChild;
|
2005-01-29 03:15:05 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
if (Node)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
Depth++;
|
|
|
|
if (Depth == 22)
|
|
|
|
{
|
|
|
|
MmRebalanceTree(AddressSpace);
|
|
|
|
PreviousNode = Node->Parent;
|
|
|
|
}
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
while (Node != NULL);
|
1998-09-05 17:33:57 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
marea->LeftChild = marea->RightChild = NULL;
|
|
|
|
marea->Parent = PreviousNode;
|
|
|
|
if (marea->StartingAddress < PreviousNode->StartingAddress)
|
|
|
|
PreviousNode->LeftChild = marea;
|
|
|
|
else
|
|
|
|
PreviousNode->RightChild = marea;
|
|
|
|
}
|
2003-05-17 15:29:50 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
static PVOID
|
|
|
|
MmFindGapBottomUp(
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
2005-01-02 17:55:06 +00:00
|
|
|
ULONG_PTR Length,
|
|
|
|
ULONG_PTR Granularity)
|
2003-05-17 15:29:50 +00:00
|
|
|
{
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PVOID LowestAddress = MmGetAddressSpaceOwner(AddressSpace) ? MM_LOWEST_USER_ADDRESS : MmSystemRangeStart;
|
|
|
|
PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ?
|
2005-07-06 08:20:26 +00:00
|
|
|
(PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
|
2005-01-02 17:55:06 +00:00
|
|
|
PVOID AlignedAddress;
|
|
|
|
PMEMORY_AREA Node;
|
|
|
|
PMEMORY_AREA FirstNode;
|
|
|
|
PMEMORY_AREA PreviousNode;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("LowestAddress: %p HighestAddress: %p\n",
|
More over-engineering: there really isn't any reason to keep track of the "LowestAddress" of the process' addres space. At first sight, this looked like a dynamic value that would define the
lowest address at which the process has allocated memory, but this isn't the case -- the variable actually defines the lowest valid address a process can allocate memory at. This is pretty
much a static value, that was compute by MmInitializeProcessAddressSpace, to either MM_LOWEST_USER_ADDRESS or MmSystemRangeStart, based on whether or not the address space has an owner process
(meaning it is a user-mode address space) or not (meaning it is a kernel mode address space).
This patch removes that value and all the complex code around checking it, and replaces it with a much simpler design: if there is an owner process, use MM_LOWEST_USER_ADDRESS during gap
calculations, otherwise, use MmSystemRangeStart. This is both faster, and wastes less space by not tracking static data.
svn path=/trunk/; revision=34869
2008-07-27 23:03:20 +00:00
|
|
|
LowestAddress, HighestAddress);
|
2004-09-28 19:49:21 +00:00
|
|
|
|
More over-engineering: there really isn't any reason to keep track of the "LowestAddress" of the process' addres space. At first sight, this looked like a dynamic value that would define the
lowest address at which the process has allocated memory, but this isn't the case -- the variable actually defines the lowest valid address a process can allocate memory at. This is pretty
much a static value, that was compute by MmInitializeProcessAddressSpace, to either MM_LOWEST_USER_ADDRESS or MmSystemRangeStart, based on whether or not the address space has an owner process
(meaning it is a user-mode address space) or not (meaning it is a kernel mode address space).
This patch removes that value and all the complex code around checking it, and replaces it with a much simpler design: if there is an owner process, use MM_LOWEST_USER_ADDRESS during gap
calculations, otherwise, use MmSystemRangeStart. This is both faster, and wastes less space by not tracking static data.
svn path=/trunk/; revision=34869
2008-07-27 23:03:20 +00:00
|
|
|
AlignedAddress = MM_ROUND_UP(LowestAddress, Granularity);
|
2005-01-02 17:55:06 +00:00
|
|
|
|
|
|
|
/* Special case for empty tree. */
|
2009-04-27 10:12:57 +00:00
|
|
|
if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
if ((ULONG_PTR)HighestAddress - (ULONG_PTR)AlignedAddress >= Length)
|
2005-01-02 17:55:06 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
|
2005-01-02 17:55:06 +00:00
|
|
|
return AlignedAddress;
|
|
|
|
}
|
|
|
|
DPRINT("MmFindGapBottomUp: 0\n");
|
|
|
|
return 0;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2003-05-17 15:29:50 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
/* Go to the node with lowest address in the tree. */
|
2009-04-27 10:12:57 +00:00
|
|
|
FirstNode = Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
|
2003-05-17 15:29:50 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
/* Traverse the tree from left to right. */
|
|
|
|
PreviousNode = Node;
|
|
|
|
for (;;)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
Node = MmIterateNextNode(Node);
|
|
|
|
if (Node == NULL)
|
|
|
|
break;
|
2003-05-17 15:29:50 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
AlignedAddress = MM_ROUND_UP(PreviousNode->EndingAddress, Granularity);
|
|
|
|
if (Node->StartingAddress > AlignedAddress &&
|
2005-01-12 10:05:31 +00:00
|
|
|
(ULONG_PTR)Node->StartingAddress - (ULONG_PTR)AlignedAddress >= Length)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
|
2005-01-02 17:55:06 +00:00
|
|
|
return AlignedAddress;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
|
|
|
|
PreviousNode = Node;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2003-05-17 15:29:50 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
/* Check if there is enough space after the last memory area. */
|
|
|
|
AlignedAddress = MM_ROUND_UP(PreviousNode->EndingAddress, Granularity);
|
2005-03-20 12:04:30 +00:00
|
|
|
if ((ULONG_PTR)HighestAddress > (ULONG_PTR)AlignedAddress &&
|
|
|
|
(ULONG_PTR)HighestAddress - (ULONG_PTR)AlignedAddress >= Length)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
|
2005-01-02 17:55:06 +00:00
|
|
|
return AlignedAddress;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
|
|
|
|
/* Check if there is enough space before the first memory area. */
|
More over-engineering: there really isn't any reason to keep track of the "LowestAddress" of the process' addres space. At first sight, this looked like a dynamic value that would define the
lowest address at which the process has allocated memory, but this isn't the case -- the variable actually defines the lowest valid address a process can allocate memory at. This is pretty
much a static value, that was compute by MmInitializeProcessAddressSpace, to either MM_LOWEST_USER_ADDRESS or MmSystemRangeStart, based on whether or not the address space has an owner process
(meaning it is a user-mode address space) or not (meaning it is a kernel mode address space).
This patch removes that value and all the complex code around checking it, and replaces it with a much simpler design: if there is an owner process, use MM_LOWEST_USER_ADDRESS during gap
calculations, otherwise, use MmSystemRangeStart. This is both faster, and wastes less space by not tracking static data.
svn path=/trunk/; revision=34869
2008-07-27 23:03:20 +00:00
|
|
|
AlignedAddress = MM_ROUND_UP(LowestAddress, Granularity);
|
2005-01-02 17:55:06 +00:00
|
|
|
if (FirstNode->StartingAddress > AlignedAddress &&
|
2005-01-12 10:05:31 +00:00
|
|
|
(ULONG_PTR)FirstNode->StartingAddress - (ULONG_PTR)AlignedAddress >= Length)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
|
2005-01-02 17:55:06 +00:00
|
|
|
return AlignedAddress;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2003-05-17 15:29:50 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
DPRINT("MmFindGapBottomUp: 0\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static PVOID
|
|
|
|
MmFindGapTopDown(
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
2005-01-02 17:55:06 +00:00
|
|
|
ULONG_PTR Length,
|
|
|
|
ULONG_PTR Granularity)
|
|
|
|
{
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PVOID LowestAddress = MmGetAddressSpaceOwner(AddressSpace) ? MM_LOWEST_USER_ADDRESS : MmSystemRangeStart;
|
|
|
|
PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ?
|
2005-07-06 08:20:26 +00:00
|
|
|
(PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
|
2005-01-02 17:55:06 +00:00
|
|
|
PVOID AlignedAddress;
|
|
|
|
PMEMORY_AREA Node;
|
|
|
|
PMEMORY_AREA PreviousNode;
|
|
|
|
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("LowestAddress: %p HighestAddress: %p\n",
|
More over-engineering: there really isn't any reason to keep track of the "LowestAddress" of the process' addres space. At first sight, this looked like a dynamic value that would define the
lowest address at which the process has allocated memory, but this isn't the case -- the variable actually defines the lowest valid address a process can allocate memory at. This is pretty
much a static value, that was compute by MmInitializeProcessAddressSpace, to either MM_LOWEST_USER_ADDRESS or MmSystemRangeStart, based on whether or not the address space has an owner process
(meaning it is a user-mode address space) or not (meaning it is a kernel mode address space).
This patch removes that value and all the complex code around checking it, and replaces it with a much simpler design: if there is an owner process, use MM_LOWEST_USER_ADDRESS during gap
calculations, otherwise, use MmSystemRangeStart. This is both faster, and wastes less space by not tracking static data.
svn path=/trunk/; revision=34869
2008-07-27 23:03:20 +00:00
|
|
|
LowestAddress, HighestAddress);
|
2005-01-02 17:55:06 +00:00
|
|
|
|
2005-01-12 10:05:31 +00:00
|
|
|
AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)HighestAddress - Length + 1, Granularity);
|
2005-01-02 17:55:06 +00:00
|
|
|
|
|
|
|
/* Check for overflow. */
|
|
|
|
if (AlignedAddress > HighestAddress)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Special case for empty tree. */
|
2009-04-27 10:12:57 +00:00
|
|
|
if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
More over-engineering: there really isn't any reason to keep track of the "LowestAddress" of the process' addres space. At first sight, this looked like a dynamic value that would define the
lowest address at which the process has allocated memory, but this isn't the case -- the variable actually defines the lowest valid address a process can allocate memory at. This is pretty
much a static value, that was compute by MmInitializeProcessAddressSpace, to either MM_LOWEST_USER_ADDRESS or MmSystemRangeStart, based on whether or not the address space has an owner process
(meaning it is a user-mode address space) or not (meaning it is a kernel mode address space).
This patch removes that value and all the complex code around checking it, and replaces it with a much simpler design: if there is an owner process, use MM_LOWEST_USER_ADDRESS during gap
calculations, otherwise, use MmSystemRangeStart. This is both faster, and wastes less space by not tracking static data.
svn path=/trunk/; revision=34869
2008-07-27 23:03:20 +00:00
|
|
|
if (AlignedAddress >= LowestAddress)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
|
2005-01-02 17:55:06 +00:00
|
|
|
return AlignedAddress;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
DPRINT("MmFindGapTopDown: 0\n");
|
|
|
|
return 0;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
|
|
|
|
/* Go to the node with highest address in the tree. */
|
2009-04-27 10:12:57 +00:00
|
|
|
Node = MmIterateLastNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
|
2005-01-02 17:55:06 +00:00
|
|
|
|
|
|
|
/* Check if there is enough space after the last memory area. */
|
|
|
|
if (Node->EndingAddress <= AlignedAddress)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
|
2005-01-02 17:55:06 +00:00
|
|
|
return AlignedAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Traverse the tree from left to right. */
|
|
|
|
PreviousNode = Node;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
Node = MmIteratePrevNode(Node);
|
|
|
|
if (Node == NULL)
|
|
|
|
break;
|
|
|
|
|
2005-01-12 10:05:31 +00:00
|
|
|
AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)PreviousNode->StartingAddress - Length + 1, Granularity);
|
2005-01-02 17:55:06 +00:00
|
|
|
|
|
|
|
/* Check for overflow. */
|
|
|
|
if (AlignedAddress > PreviousNode->StartingAddress)
|
2004-04-10 22:36:07 +00:00
|
|
|
return NULL;
|
2005-01-29 03:15:05 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
if (Node->EndingAddress <= AlignedAddress)
|
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
|
2005-01-02 17:55:06 +00:00
|
|
|
return AlignedAddress;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
|
|
|
|
PreviousNode = Node;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
2005-01-12 10:05:31 +00:00
|
|
|
AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)PreviousNode->StartingAddress - Length + 1, Granularity);
|
2005-01-02 17:55:06 +00:00
|
|
|
|
|
|
|
/* Check for overflow. */
|
|
|
|
if (AlignedAddress > PreviousNode->StartingAddress)
|
|
|
|
return NULL;
|
|
|
|
|
More over-engineering: there really isn't any reason to keep track of the "LowestAddress" of the process' addres space. At first sight, this looked like a dynamic value that would define the
lowest address at which the process has allocated memory, but this isn't the case -- the variable actually defines the lowest valid address a process can allocate memory at. This is pretty
much a static value, that was compute by MmInitializeProcessAddressSpace, to either MM_LOWEST_USER_ADDRESS or MmSystemRangeStart, based on whether or not the address space has an owner process
(meaning it is a user-mode address space) or not (meaning it is a kernel mode address space).
This patch removes that value and all the complex code around checking it, and replaces it with a much simpler design: if there is an owner process, use MM_LOWEST_USER_ADDRESS during gap
calculations, otherwise, use MmSystemRangeStart. This is both faster, and wastes less space by not tracking static data.
svn path=/trunk/; revision=34869
2008-07-27 23:03:20 +00:00
|
|
|
if (AlignedAddress >= LowestAddress)
|
2005-01-02 17:55:06 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
|
2005-01-02 17:55:06 +00:00
|
|
|
return AlignedAddress;
|
|
|
|
}
|
|
|
|
|
|
|
|
DPRINT("MmFindGapTopDown: 0\n");
|
|
|
|
return 0;
|
2003-05-17 15:29:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
PVOID NTAPI
|
2005-01-02 17:55:06 +00:00
|
|
|
MmFindGap(
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
2005-01-02 17:55:06 +00:00
|
|
|
ULONG_PTR Length,
|
|
|
|
ULONG_PTR Granularity,
|
|
|
|
BOOLEAN TopDown)
|
2003-05-17 15:29:50 +00:00
|
|
|
{
|
2004-04-10 22:36:07 +00:00
|
|
|
if (TopDown)
|
2004-09-28 19:49:21 +00:00
|
|
|
return MmFindGapTopDown(AddressSpace, Length, Granularity);
|
2003-05-17 15:29:50 +00:00
|
|
|
|
2004-09-28 19:49:21 +00:00
|
|
|
return MmFindGapBottomUp(AddressSpace, Length, Granularity);
|
2003-05-17 15:29:50 +00:00
|
|
|
}
|
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
ULONG_PTR NTAPI
|
2005-01-02 17:55:06 +00:00
|
|
|
MmFindGapAtAddress(
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
2005-01-02 17:55:06 +00:00
|
|
|
PVOID Address)
|
2004-07-10 17:01:03 +00:00
|
|
|
{
|
2009-04-27 10:12:57 +00:00
|
|
|
PMEMORY_AREA Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
|
2005-01-02 17:55:06 +00:00
|
|
|
PMEMORY_AREA RightNeighbour = NULL;
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
PVOID LowestAddress = MmGetAddressSpaceOwner(AddressSpace) ? MM_LOWEST_USER_ADDRESS : MmSystemRangeStart;
|
|
|
|
PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ?
|
2005-07-06 08:20:26 +00:00
|
|
|
(PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
|
2005-01-02 17:55:06 +00:00
|
|
|
|
|
|
|
Address = MM_ROUND_DOWN(Address, PAGE_SIZE);
|
2004-07-10 17:01:03 +00:00
|
|
|
|
More over-engineering: there really isn't any reason to keep track of the "LowestAddress" of the process' addres space. At first sight, this looked like a dynamic value that would define the
lowest address at which the process has allocated memory, but this isn't the case -- the variable actually defines the lowest valid address a process can allocate memory at. This is pretty
much a static value, that was compute by MmInitializeProcessAddressSpace, to either MM_LOWEST_USER_ADDRESS or MmSystemRangeStart, based on whether or not the address space has an owner process
(meaning it is a user-mode address space) or not (meaning it is a kernel mode address space).
This patch removes that value and all the complex code around checking it, and replaces it with a much simpler design: if there is an owner process, use MM_LOWEST_USER_ADDRESS during gap
calculations, otherwise, use MmSystemRangeStart. This is both faster, and wastes less space by not tracking static data.
svn path=/trunk/; revision=34869
2008-07-27 23:03:20 +00:00
|
|
|
if (LowestAddress < MmSystemRangeStart)
|
2004-07-10 17:01:03 +00:00
|
|
|
{
|
2005-07-06 08:20:26 +00:00
|
|
|
if (Address >= MmSystemRangeStart)
|
2004-07-10 17:01:03 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
More over-engineering: there really isn't any reason to keep track of the "LowestAddress" of the process' addres space. At first sight, this looked like a dynamic value that would define the
lowest address at which the process has allocated memory, but this isn't the case -- the variable actually defines the lowest valid address a process can allocate memory at. This is pretty
much a static value, that was compute by MmInitializeProcessAddressSpace, to either MM_LOWEST_USER_ADDRESS or MmSystemRangeStart, based on whether or not the address space has an owner process
(meaning it is a user-mode address space) or not (meaning it is a kernel mode address space).
This patch removes that value and all the complex code around checking it, and replaces it with a much simpler design: if there is an owner process, use MM_LOWEST_USER_ADDRESS during gap
calculations, otherwise, use MmSystemRangeStart. This is both faster, and wastes less space by not tracking static data.
svn path=/trunk/; revision=34869
2008-07-27 23:03:20 +00:00
|
|
|
if (Address < LowestAddress)
|
2004-07-10 17:01:03 +00:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
while (Node != NULL)
|
2004-07-10 17:01:03 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
if (Address < Node->StartingAddress)
|
2004-07-10 17:01:03 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
RightNeighbour = Node;
|
|
|
|
Node = Node->LeftChild;
|
2004-07-10 17:01:03 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
else if (Address >= Node->EndingAddress)
|
2004-07-10 17:01:03 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
Node = Node->RightChild;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DPRINT("MmFindGapAtAddress: 0\n");
|
|
|
|
return 0;
|
2004-07-10 17:01:03 +00:00
|
|
|
}
|
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
|
|
|
|
if (RightNeighbour)
|
2004-07-10 17:01:03 +00:00
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmFindGapAtAddress: %p [%p]\n", Address,
|
|
|
|
(ULONG_PTR)RightNeighbour->StartingAddress - (ULONG_PTR)Address);
|
|
|
|
return (ULONG_PTR)RightNeighbour->StartingAddress - (ULONG_PTR)Address;
|
2004-07-10 17:01:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmFindGapAtAddress: %p [%p]\n", Address,
|
|
|
|
(ULONG_PTR)HighestAddress - (ULONG_PTR)Address);
|
|
|
|
return (ULONG_PTR)HighestAddress - (ULONG_PTR)Address;
|
2004-07-10 17:01:03 +00:00
|
|
|
}
|
|
|
|
}
|
2003-05-17 15:29:50 +00:00
|
|
|
|
2010-10-05 05:07:13 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
MiRemoveNode(IN PMMADDRESS_NODE Node,
|
|
|
|
IN PMM_AVL_TABLE Table);
|
2005-01-02 17:55:06 +00:00
|
|
|
|
2005-01-11 22:15:41 +00:00
|
|
|
/**
|
2005-01-02 17:55:06 +00:00
|
|
|
* @name MmFreeMemoryArea
|
|
|
|
*
|
|
|
|
* Free an existing memory area.
|
|
|
|
*
|
2005-01-29 03:15:05 +00:00
|
|
|
* @param AddressSpace
|
2005-01-02 17:55:06 +00:00
|
|
|
* Address space to free the area from.
|
|
|
|
* @param MemoryArea
|
|
|
|
* Memory area we're about to free.
|
|
|
|
* @param FreePage
|
|
|
|
* Callback function for each freed page.
|
|
|
|
* @param FreePageContext
|
|
|
|
* Context passed to the callback function.
|
|
|
|
*
|
|
|
|
* @return Status
|
|
|
|
*
|
|
|
|
* @remarks Lock the address space before calling this function.
|
|
|
|
*/
|
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2005-01-02 17:55:06 +00:00
|
|
|
MmFreeMemoryArea(
|
2009-04-27 10:12:57 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
2005-01-02 17:55:06 +00:00
|
|
|
PMEMORY_AREA MemoryArea,
|
|
|
|
PMM_FREE_PAGE_FUNC FreePage,
|
|
|
|
PVOID FreePageContext)
|
1998-09-05 17:33:57 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
PMEMORY_AREA *ParentReplace;
|
2005-01-12 10:05:31 +00:00
|
|
|
ULONG_PTR Address;
|
2005-01-02 17:55:06 +00:00
|
|
|
PVOID EndAddress;
|
2010-07-21 17:58:09 +00:00
|
|
|
|
|
|
|
if (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2010-07-21 17:58:09 +00:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
BOOLEAN Dirty = FALSE;
|
|
|
|
SWAPENTRY SwapEntry = 0;
|
|
|
|
PFN_NUMBER Page = 0;
|
|
|
|
|
|
|
|
if (MmIsPageSwapEntry(Process, (PVOID)Address))
|
|
|
|
{
|
|
|
|
MmDeletePageFileMapping(Process, (PVOID)Address, &SwapEntry);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MmDeleteVirtualMapping(Process, (PVOID)Address, FALSE, &Dirty, &Page);
|
|
|
|
}
|
|
|
|
if (FreePage != NULL)
|
|
|
|
{
|
|
|
|
FreePage(FreePageContext, MemoryArea, (PVOID)Address,
|
|
|
|
Page, SwapEntry, (BOOLEAN)Dirty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Process != NULL &&
|
|
|
|
Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeDetachProcess();
|
|
|
|
}
|
2010-10-05 05:07:13 +00:00
|
|
|
|
|
|
|
if (MemoryArea->Vad)
|
|
|
|
{
|
|
|
|
ASSERT(MemoryArea->EndingAddress < MmSystemRangeStart);
|
|
|
|
ASSERT(MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY || MemoryArea->Type == MEMORY_AREA_SECTION_VIEW);
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
ExFreePool(MemoryArea->Vad);
|
|
|
|
MemoryArea->Vad = NULL;
|
|
|
|
}
|
2010-07-21 17:58:09 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
|
2005-01-29 03:15:05 +00:00
|
|
|
/* Remove the tree item. */
|
2005-01-02 17:55:06 +00:00
|
|
|
{
|
|
|
|
if (MemoryArea->Parent != NULL)
|
|
|
|
{
|
|
|
|
if (MemoryArea->Parent->LeftChild == MemoryArea)
|
|
|
|
ParentReplace = &MemoryArea->Parent->LeftChild;
|
|
|
|
else
|
|
|
|
ParentReplace = &MemoryArea->Parent->RightChild;
|
|
|
|
}
|
|
|
|
else
|
2009-04-27 10:12:57 +00:00
|
|
|
ParentReplace = (PMEMORY_AREA*)&AddressSpace->WorkingSetExpansionLinks.Flink;
|
2005-01-02 17:55:06 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-05-05 17:20:10 +00:00
|
|
|
ExFreePoolWithTag(MemoryArea, TAG_MAREA);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
DPRINT("MmFreeMemoryAreaByNode() succeeded\n");
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
return STATUS_SUCCESS;
|
1998-09-05 17:33:57 +00:00
|
|
|
}
|
|
|
|
|
2005-01-11 22:15:41 +00:00
|
|
|
/**
|
2005-01-02 17:55:06 +00:00
|
|
|
* @name MmCreateMemoryArea
|
|
|
|
*
|
|
|
|
* Create a memory area.
|
|
|
|
*
|
2005-01-29 03:15:05 +00:00
|
|
|
* @param AddressSpace
|
2005-01-02 17:55:06 +00:00
|
|
|
* Address space to create the area in.
|
|
|
|
* @param Type
|
|
|
|
* Type of the memory area.
|
|
|
|
* @param BaseAddress
|
|
|
|
* Base address for the memory area we're about the create. On
|
|
|
|
* input it contains either 0 (auto-assign address) or preferred
|
|
|
|
* address. On output it contains the starting address of the
|
|
|
|
* newly created area.
|
|
|
|
* @param Length
|
|
|
|
* Length of the area to allocate.
|
|
|
|
* @param Attributes
|
|
|
|
* Protection attributes for the memory area.
|
|
|
|
* @param Result
|
|
|
|
* Receives a pointer to the memory area on successful exit.
|
|
|
|
*
|
|
|
|
* @return Status
|
|
|
|
*
|
|
|
|
* @remarks Lock the address space before calling this function.
|
|
|
|
*/
|
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
NTSTATUS NTAPI
|
2009-04-27 10:12:57 +00:00
|
|
|
MmCreateMemoryArea(PMMSUPPORT AddressSpace,
|
2005-01-02 17:55:06 +00:00
|
|
|
ULONG Type,
|
|
|
|
PVOID *BaseAddress,
|
|
|
|
ULONG_PTR Length,
|
2005-11-13 17:28:24 +00:00
|
|
|
ULONG Protect,
|
2005-01-02 17:55:06 +00:00
|
|
|
PMEMORY_AREA *Result,
|
|
|
|
BOOLEAN FixedAddress,
|
2005-11-13 17:28:24 +00:00
|
|
|
ULONG AllocationFlags,
|
2005-01-02 17:55:06 +00:00
|
|
|
PHYSICAL_ADDRESS BoundaryAddressMultiple)
|
1998-09-05 17:33:57 +00:00
|
|
|
{
|
2003-12-31 05:33:04 +00:00
|
|
|
PVOID EndAddress;
|
2004-09-28 19:49:21 +00:00
|
|
|
ULONG Granularity;
|
2002-11-05 20:43:35 +00:00
|
|
|
ULONG tmpLength;
|
2005-01-02 17:55:06 +00:00
|
|
|
PMEMORY_AREA MemoryArea;
|
|
|
|
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
|
2006-09-07 21:36:15 +00:00
|
|
|
"*BaseAddress %p, Length %p, AllocationFlags %x, "
|
2005-01-12 10:05:31 +00:00
|
|
|
"FixedAddress %x, Result %p)\n",
|
2006-09-07 21:36:15 +00:00
|
|
|
Type, BaseAddress, *BaseAddress, Length, AllocationFlags,
|
2005-01-02 17:55:06 +00:00
|
|
|
FixedAddress, Result);
|
|
|
|
|
2004-09-28 19:49:21 +00:00
|
|
|
Granularity = (MEMORY_AREA_VIRTUAL_MEMORY == Type ? MM_VIRTMEM_GRANULARITY : PAGE_SIZE);
|
2003-05-17 15:29:50 +00:00
|
|
|
if ((*BaseAddress) == 0 && !FixedAddress)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
tmpLength = PAGE_ROUND_UP(Length);
|
|
|
|
*BaseAddress = MmFindGap(AddressSpace,
|
2005-01-02 17:55:06 +00:00
|
|
|
tmpLength,
|
2004-09-28 19:49:21 +00:00
|
|
|
Granularity,
|
2005-11-13 17:28:24 +00:00
|
|
|
(AllocationFlags & MEM_TOP_DOWN) == MEM_TOP_DOWN);
|
2004-04-10 22:36:07 +00:00
|
|
|
if ((*BaseAddress) == 0)
|
|
|
|
{
|
|
|
|
DPRINT("No suitable gap\n");
|
2004-09-28 19:49:21 +00:00
|
|
|
return STATUS_NO_MEMORY;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
1998-09-05 17:33:57 +00:00
|
|
|
else
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
2005-01-02 17:55:06 +00:00
|
|
|
tmpLength = Length + ((ULONG_PTR) *BaseAddress
|
|
|
|
- (ULONG_PTR) MM_ROUND_DOWN(*BaseAddress, Granularity));
|
2004-10-01 20:26:05 +00:00
|
|
|
*BaseAddress = MM_ROUND_DOWN(*BaseAddress, Granularity);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
if (!MmGetAddressSpaceOwner(AddressSpace) && *BaseAddress < MmSystemRangeStart)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
return STATUS_ACCESS_VIOLATION;
|
|
|
|
}
|
|
|
|
|
The puzzle of the design decisions behind the React address space structure continues to be troubling (perhaps there was no design?). Every time a process address space is initialized,
the owner process is stored (which we now use to figure out the lowest address). Recall that NULL means kernel, anything else means per-process. This is great, except that after some
painfull header groking, one understands that the PMADDRESS_SPACE structure is actually *not* a separate structure, but embedded within PEPROCESS itself. It is a React-specific structure
(hence the attempts to get rid of it), that seems to have been "overloaded" on top of the VadRoot structure that Windows uses for user-mode memory allocations. To clarify, this structure
is actually embedded inside the process that owns it, except for the kernel address space, which is a global variable. So there's absolutely *no* point in saving a reference to the owner
process, since we'll always be embedded inside it (except for kernel address space).
This patch creates the MmGetAddressSpaceOwner macro which either returns NULL for kernel address space, or uses the CONTAINING_RECORD macro to return the owner (embedded) process.
svn path=/trunk/; revision=34873
2008-07-27 23:53:04 +00:00
|
|
|
if (MmGetAddressSpaceOwner(AddressSpace) &&
|
2005-07-06 08:20:26 +00:00
|
|
|
(ULONG_PTR)(*BaseAddress) + tmpLength > (ULONG_PTR)MmSystemRangeStart)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
return STATUS_ACCESS_VIOLATION;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (BoundaryAddressMultiple.QuadPart != 0)
|
|
|
|
{
|
|
|
|
EndAddress = ((char*)(*BaseAddress)) + tmpLength-1;
|
2005-01-02 17:55:06 +00:00
|
|
|
ASSERT(((ULONG_PTR)*BaseAddress/BoundaryAddressMultiple.QuadPart) == ((DWORD_PTR)EndAddress/BoundaryAddressMultiple.QuadPart));
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
|
2005-01-02 19:14:52 +00:00
|
|
|
if (MmLocateMemoryAreaByRegion(AddressSpace,
|
|
|
|
*BaseAddress,
|
|
|
|
tmpLength) != NULL)
|
2004-04-10 22:36:07 +00:00
|
|
|
{
|
|
|
|
DPRINT("Memory area already occupied\n");
|
2004-09-28 19:49:21 +00:00
|
|
|
return STATUS_CONFLICTING_ADDRESSES;
|
2004-04-10 22:36:07 +00:00
|
|
|
}
|
|
|
|
}
|
2009-06-21 05:46:50 +00:00
|
|
|
|
|
|
|
//
|
|
|
|
// Is this a static memory area?
|
|
|
|
//
|
|
|
|
if (Type & MEMORY_AREA_STATIC)
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// Use the static array instead of the pool
|
|
|
|
//
|
|
|
|
ASSERT(MiStaticMemoryAreaCount < MI_STATIC_MEMORY_AREAS);
|
|
|
|
MemoryArea = &MiStaticMemoryAreas[MiStaticMemoryAreaCount++];
|
- Fix a bug in memory area creation: Static memory areas had the static flag embedded in their type, so code that was switch()ing on the type would fail to recognize the actual type, because MEMORY_AREA_STATIC was ORed in.
- Add a new memory area type: MEMORY_AREA_OWNED_BY_ARM3. This will allow us to instruct the ReactOS Memory MAnager to "Back. The Fuck. Off." during page faults and such, so we can handle page faults inside ARM3-owned PTEs ourselves.
- Right now, all ARM3 PTEs and data is nonpaged, so no page faults should happen, but this may change in the future.
- Also will allow us to manage our own PDEs so we can do on-demand inpage instead of syncing with the ReactOS Mm hack cache.
- Create all memory areas in one shot in MmCreateSystemMemoryAreas (get rid of MiInitPageDirectoryMap and MiInitPagedPool memory area creation).
- Mark all of ours as owned by ARM3.
- Make them all static.
- The only non-ARM3 one right now is paged pool, we own all the other static areas.
- Move this code into mm, instead of mm/ARM3, since memory areas are not an ARM3 concept.
- Also create memory areas for session space, session view, and other ARM3 memory ranges, so nobody touches those ranges.
- Dump the kernel address space after all this is done, in a MmDbg function in mm.
- This cleans up ARM3 of some ROS-specific code, and also collapses Phase 1 and 2 into a single phase.
svn path=/trunk/; revision=43486
2009-10-15 18:54:35 +00:00
|
|
|
Type &= ~MEMORY_AREA_STATIC;
|
2009-06-21 05:46:50 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// Allocate the memory area from nonpaged pool
|
|
|
|
//
|
|
|
|
MemoryArea = ExAllocatePoolWithTag(NonPagedPool,
|
|
|
|
sizeof(MEMORY_AREA),
|
|
|
|
TAG_MAREA);
|
|
|
|
}
|
2009-09-02 13:02:30 +00:00
|
|
|
|
|
|
|
if (!MemoryArea) return STATUS_NO_MEMORY;
|
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
RtlZeroMemory(MemoryArea, sizeof(MEMORY_AREA));
|
|
|
|
MemoryArea->Type = Type;
|
|
|
|
MemoryArea->StartingAddress = *BaseAddress;
|
2005-01-12 10:05:31 +00:00
|
|
|
MemoryArea->EndingAddress = (PVOID)((ULONG_PTR)*BaseAddress + tmpLength);
|
2005-11-13 17:28:24 +00:00
|
|
|
MemoryArea->Protect = Protect;
|
|
|
|
MemoryArea->Flags = AllocationFlags;
|
2006-05-18 20:10:44 +00:00
|
|
|
//MemoryArea->LockCount = 0;
|
2005-01-02 17:55:06 +00:00
|
|
|
MemoryArea->PageOpCount = 0;
|
|
|
|
MemoryArea->DeleteInProgress = FALSE;
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
MmInsertMemoryArea(AddressSpace, MemoryArea);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
*Result = MemoryArea;
|
|
|
|
|
2005-01-12 10:05:31 +00:00
|
|
|
DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress);
|
2004-09-28 19:49:21 +00:00
|
|
|
return STATUS_SUCCESS;
|
1998-09-05 17:33:57 +00:00
|
|
|
}
|
2004-10-01 20:26:05 +00:00
|
|
|
|
2008-03-13 13:17:57 +00:00
|
|
|
VOID NTAPI
|
|
|
|
MmMapMemoryArea(PVOID BaseAddress,
|
|
|
|
ULONG Length,
|
|
|
|
ULONG Consumer,
|
|
|
|
ULONG Protection)
|
|
|
|
{
|
|
|
|
ULONG i;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
|
|
|
|
{
|
2010-07-15 22:50:12 +00:00
|
|
|
PFN_NUMBER Page;
|
2008-03-13 13:17:57 +00:00
|
|
|
|
|
|
|
Status = MmRequestPageMemoryConsumer(Consumer, TRUE, &Page);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Unable to allocate page\n");
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-03-13 13:17:57 +00:00
|
|
|
}
|
|
|
|
Status = MmCreateVirtualMapping (NULL,
|
|
|
|
(PVOID)((ULONG_PTR)BaseAddress + (i * PAGE_SIZE)),
|
|
|
|
Protection,
|
|
|
|
&Page,
|
|
|
|
1);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Unable to create virtual mapping\n");
|
2008-12-07 18:05:28 +00:00
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2008-03-13 13:17:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
MmDeleteProcessAddressSpace(PEPROCESS Process)
|
2004-10-01 20:26:05 +00:00
|
|
|
{
|
2010-10-05 15:55:52 +00:00
|
|
|
PVOID Address;
|
2005-01-02 17:55:06 +00:00
|
|
|
PMEMORY_AREA MemoryArea;
|
2005-01-29 03:15:05 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process,
|
|
|
|
Process->ImageFileName);
|
2005-01-02 17:55:06 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
RemoveEntryList(&Process->MmProcessLinks);
|
|
|
|
|
|
|
|
MmLockAddressSpace(&Process->Vm);
|
2004-10-01 20:26:05 +00:00
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
while ((MemoryArea = (PMEMORY_AREA)Process->Vm.WorkingSetExpansionLinks.Flink) != NULL)
|
|
|
|
{
|
|
|
|
switch (MemoryArea->Type)
|
2005-01-02 17:55:06 +00:00
|
|
|
{
|
2010-10-05 15:55:52 +00:00
|
|
|
case MEMORY_AREA_SECTION_VIEW:
|
|
|
|
Address = (PVOID)MemoryArea->StartingAddress;
|
|
|
|
MmUnlockAddressSpace(&Process->Vm);
|
|
|
|
MmUnmapViewOfSection(Process, Address);
|
|
|
|
MmLockAddressSpace(&Process->Vm);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MEMORY_AREA_VIRTUAL_MEMORY:
|
|
|
|
MmFreeVirtualMemory(Process, MemoryArea);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case MEMORY_AREA_OWNED_BY_ARM3:
|
|
|
|
MmFreeMemoryArea(&Process->Vm,
|
|
|
|
MemoryArea,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
KeBugCheck(MEMORY_MANAGEMENT);
|
2005-01-02 17:55:06 +00:00
|
|
|
}
|
|
|
|
}
|
2010-10-05 15:55:52 +00:00
|
|
|
|
|
|
|
MmUnlockAddressSpace(&Process->Vm);
|
|
|
|
|
|
|
|
DPRINT("Finished MmReleaseMmInfo()\n");
|
|
|
|
return(STATUS_SUCCESS);
|
2004-10-01 20:26:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|