-/* $Id$
+/*
+ * Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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.
+ *
*
- * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/mm/marea.c
* PURPOSE: Implements memory areas
*
- * PROGRAMMERS: David Welch (welch@mcmail.com)
+ * PROGRAMMERS: Rex Jolliff
+ * David Welch
+ * Eric Kohl
+ * Philip Susi
+ * Casper Hornstrup
+ * Eric Kohl
+ * Ge van Geldorp
+ * Royce Mitchell III
+ * Aleksey Bragin
+ * Jason Filby
+ * Thomas Weidenmueller
+ * Gunnar Andre' Dalsnes
+ * Mike Nordell
+ * Alex Ionescu
+ * Filip Navara
+ * Herve Poussineau
+ * Steven Edwards
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
-/* GLOBALS *******************************************************************/
-
-#define TAG_MAREA TAG('M', 'A', 'R', 'E')
+MEMORY_AREA MiStaticMemoryAreas[MI_STATIC_MEMORY_AREAS];
+ULONG MiStaticMemoryAreaCount;
/* #define VALIDATE_MEMORY_AREAS */
}
/**
- * @name MmIterateFirstNode
+ * @name MmIterateLastNode
*
* @param Node
* Head node of the MEMORY_AREA tree.
}
/**
- * @name MmIterateNextNode
+ * @name MmIteratePreviousNode
*
* @param Node
* Current node in the tree.
}
#ifdef VALIDATE_MEMORY_AREAS
-static VOID MmVerifyMemoryAreas(PMADDRESS_SPACE AddressSpace)
+static VOID MmVerifyMemoryAreas(PMMSUPPORT AddressSpace)
{
PMEMORY_AREA Node;
ASSERT(AddressSpace != NULL);
/* Special case for empty tree. */
- if (AddressSpace->MemoryAreaRoot == NULL)
+ if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
return;
/* Traverse the tree from left to right. */
- for (Node = MmIterateFirstNode(AddressSpace->MemoryAreaRoot);
+ for (Node = MmIterateFirstNode(AddressSpace->WorkingSetExpansionLinks.Flink);
Node != NULL;
Node = MmIterateNextNode(Node))
{
/* FiN: The starting address can be NULL if someone explicitely asks
* for NULL address. */
- ASSERT(Node->StartingAddress >= AddressSpace->LowestAddress ||
- Node->StartingAddress == NULL);
+ ASSERT(Node->StartingAddress == NULL);
ASSERT(Node->EndingAddress >= Node->StartingAddress);
}
}
#define MmVerifyMemoryAreas(x)
#endif
-VOID STDCALL
-MmDumpMemoryAreas(PMADDRESS_SPACE AddressSpace)
+VOID NTAPI
+MmDumpMemoryAreas(PMMSUPPORT AddressSpace)
{
PMEMORY_AREA Node;
DbgPrint("MmDumpMemoryAreas()\n");
/* Special case for empty tree. */
- if (AddressSpace->MemoryAreaRoot == NULL)
+ if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
return;
/* Traverse the tree from left to right. */
- for (Node = MmIterateFirstNode(AddressSpace->MemoryAreaRoot);
+ for (Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
Node != NULL;
Node = MmIterateNextNode(Node))
{
- DbgPrint("Start %p End %p Attributes %x\n",
+ DbgPrint("Start %p End %p Protect %x Flags %x\n",
Node->StartingAddress, Node->EndingAddress,
- Node->Attributes);
+ Node->Protect, Node->Flags);
}
DbgPrint("Finished MmDumpMemoryAreas()\n");
}
-PMEMORY_AREA STDCALL
+PMEMORY_AREA NTAPI
MmLocateMemoryAreaByAddress(
- PMADDRESS_SPACE AddressSpace,
+ PMMSUPPORT AddressSpace,
PVOID Address)
{
- PMEMORY_AREA Node = AddressSpace->MemoryAreaRoot;
+ PMEMORY_AREA Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
AddressSpace, Address);
return NULL;
}
-PMEMORY_AREA STDCALL
+PMEMORY_AREA NTAPI
MmLocateMemoryAreaByRegion(
- PMADDRESS_SPACE AddressSpace,
+ PMMSUPPORT AddressSpace,
PVOID Address,
ULONG_PTR Length)
{
MmVerifyMemoryAreas(AddressSpace);
/* Special case for empty tree. */
- if (AddressSpace->MemoryAreaRoot == NULL)
+ if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
return NULL;
/* Traverse the tree from left to right. */
- for (Node = MmIterateFirstNode(AddressSpace->MemoryAreaRoot);
+ for (Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
Node != NULL;
Node = MmIterateNextNode(Node))
{
static VOID
MmCompressHelper(
- PMADDRESS_SPACE AddressSpace,
+ PMMSUPPORT AddressSpace,
ULONG Count)
{
PMEMORY_AREA Root = NULL;
- PMEMORY_AREA Red = AddressSpace->MemoryAreaRoot;
+ PMEMORY_AREA Red = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
PMEMORY_AREA Black = Red->LeftChild;
while (Count--)
if (Root)
Root->LeftChild = Black;
else
- AddressSpace->MemoryAreaRoot = Black;
+ AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)Black;
Black->Parent = Root;
Red->LeftChild = Black->RightChild;
if (Black->RightChild)
static VOID
MmRebalanceTree(
- PMADDRESS_SPACE AddressSpace)
+ PMMSUPPORT AddressSpace)
{
PMEMORY_AREA PreviousNode;
PMEMORY_AREA CurrentNode;
/* Transform the tree into Vine. */
PreviousNode = NULL;
- CurrentNode = AddressSpace->MemoryAreaRoot;
+ CurrentNode = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
while (CurrentNode != NULL)
{
if (CurrentNode->RightChild == NULL)
if (PreviousNode != NULL)
PreviousNode->LeftChild = TempNode;
else
- AddressSpace->MemoryAreaRoot = TempNode;
+ AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)TempNode;
TempNode->Parent = PreviousNode;
}
}
static VOID
MmInsertMemoryArea(
- PMADDRESS_SPACE AddressSpace,
+ PMMSUPPORT AddressSpace,
PMEMORY_AREA marea)
{
PMEMORY_AREA Node;
MmVerifyMemoryAreas(AddressSpace);
- if (AddressSpace->MemoryAreaRoot == NULL)
+ if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
{
- AddressSpace->MemoryAreaRoot = marea;
+ AddressSpace->WorkingSetExpansionLinks.Flink = (PVOID)marea;
marea->LeftChild = marea->RightChild = marea->Parent = NULL;
return;
}
- Node = AddressSpace->MemoryAreaRoot;
+ Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
do
{
DPRINT("marea->EndingAddress: %p Node->StartingAddress: %p\n",
static PVOID
MmFindGapBottomUp(
- PMADDRESS_SPACE AddressSpace,
+ PMMSUPPORT AddressSpace,
ULONG_PTR Length,
ULONG_PTR Granularity)
{
- PVOID HighestAddress = AddressSpace->LowestAddress < (PVOID)KERNEL_BASE ?
- (PVOID)(KERNEL_BASE - 1) : (PVOID)MAXULONG_PTR;
+ PVOID LowestAddress = MmGetAddressSpaceOwner(AddressSpace) ? MM_LOWEST_USER_ADDRESS : MmSystemRangeStart;
+ PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ?
+ (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
PVOID AlignedAddress;
PMEMORY_AREA Node;
PMEMORY_AREA FirstNode;
MmVerifyMemoryAreas(AddressSpace);
DPRINT("LowestAddress: %p HighestAddress: %p\n",
- AddressSpace->LowestAddress, HighestAddress);
+ LowestAddress, HighestAddress);
- AlignedAddress = MM_ROUND_UP(AddressSpace->LowestAddress, Granularity);
+ AlignedAddress = MM_ROUND_UP(LowestAddress, Granularity);
/* Special case for empty tree. */
- if (AddressSpace->MemoryAreaRoot == NULL)
+ if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
{
if ((ULONG_PTR)HighestAddress - (ULONG_PTR)AlignedAddress >= Length)
{
}
/* Go to the node with lowest address in the tree. */
- FirstNode = Node = MmIterateFirstNode(AddressSpace->MemoryAreaRoot);
+ FirstNode = Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
/* Traverse the tree from left to right. */
PreviousNode = Node;
}
/* Check if there is enough space before the first memory area. */
- AlignedAddress = MM_ROUND_UP(AddressSpace->LowestAddress, Granularity);
+ AlignedAddress = MM_ROUND_UP(LowestAddress, Granularity);
if (FirstNode->StartingAddress > AlignedAddress &&
(ULONG_PTR)FirstNode->StartingAddress - (ULONG_PTR)AlignedAddress >= Length)
{
static PVOID
MmFindGapTopDown(
- PMADDRESS_SPACE AddressSpace,
+ PMMSUPPORT AddressSpace,
ULONG_PTR Length,
ULONG_PTR Granularity)
{
- PVOID HighestAddress = AddressSpace->LowestAddress < (PVOID)KERNEL_BASE ?
- (PVOID)(KERNEL_BASE - 1) : (PVOID)MAXULONG_PTR;
+ PVOID LowestAddress = MmGetAddressSpaceOwner(AddressSpace) ? MM_LOWEST_USER_ADDRESS : MmSystemRangeStart;
+ PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ?
+ (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
PVOID AlignedAddress;
PMEMORY_AREA Node;
PMEMORY_AREA PreviousNode;
MmVerifyMemoryAreas(AddressSpace);
DPRINT("LowestAddress: %p HighestAddress: %p\n",
- AddressSpace->LowestAddress, HighestAddress);
+ LowestAddress, HighestAddress);
AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)HighestAddress - Length + 1, Granularity);
return NULL;
/* Special case for empty tree. */
- if (AddressSpace->MemoryAreaRoot == NULL)
+ if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
{
- if (AlignedAddress >= (PVOID)AddressSpace->LowestAddress)
+ if (AlignedAddress >= LowestAddress)
{
DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
return AlignedAddress;
}
/* Go to the node with highest address in the tree. */
- Node = MmIterateLastNode(AddressSpace->MemoryAreaRoot);
+ Node = MmIterateLastNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
/* Check if there is enough space after the last memory area. */
if (Node->EndingAddress <= AlignedAddress)
if (AlignedAddress > PreviousNode->StartingAddress)
return NULL;
- if (AlignedAddress >= (PVOID)AddressSpace->LowestAddress)
+ if (AlignedAddress >= LowestAddress)
{
DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
return AlignedAddress;
}
-PVOID STDCALL
+PVOID NTAPI
MmFindGap(
- PMADDRESS_SPACE AddressSpace,
+ PMMSUPPORT AddressSpace,
ULONG_PTR Length,
ULONG_PTR Granularity,
BOOLEAN TopDown)
return MmFindGapBottomUp(AddressSpace, Length, Granularity);
}
-ULONG_PTR STDCALL
+ULONG_PTR NTAPI
MmFindGapAtAddress(
- PMADDRESS_SPACE AddressSpace,
+ PMMSUPPORT AddressSpace,
PVOID Address)
{
- PMEMORY_AREA Node = AddressSpace->MemoryAreaRoot;
+ PMEMORY_AREA Node = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
PMEMORY_AREA RightNeighbour = NULL;
- PVOID HighestAddress = AddressSpace->LowestAddress < (PVOID)KERNEL_BASE ?
- (PVOID)(KERNEL_BASE - 1) : (PVOID)MAXULONG_PTR;
+ PVOID LowestAddress = MmGetAddressSpaceOwner(AddressSpace) ? MM_LOWEST_USER_ADDRESS : MmSystemRangeStart;
+ PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ?
+ (PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
MmVerifyMemoryAreas(AddressSpace);
Address = MM_ROUND_DOWN(Address, PAGE_SIZE);
- if (AddressSpace->LowestAddress < (PVOID)KERNEL_BASE)
+ if (LowestAddress < MmSystemRangeStart)
{
- if (Address >= (PVOID)KERNEL_BASE)
+ if (Address >= MmSystemRangeStart)
{
return 0;
}
}
else
{
- if (Address < AddressSpace->LowestAddress)
+ if (Address < LowestAddress)
{
return 0;
}
}
}
-/**
- * @name MmInitMemoryAreas
- *
- * Initialize the memory area list implementation.
- */
-
-NTSTATUS INIT_FUNCTION
-MmInitMemoryAreas(VOID)
-{
- DPRINT("MmInitMemoryAreas()\n",0);
- return(STATUS_SUCCESS);
-}
-
/**
* @name MmFreeMemoryArea
* @remarks Lock the address space before calling this function.
*/
-NTSTATUS STDCALL
+NTSTATUS NTAPI
MmFreeMemoryArea(
- PMADDRESS_SPACE AddressSpace,
+ PMMSUPPORT AddressSpace,
PMEMORY_AREA MemoryArea,
PMM_FREE_PAGE_FUNC FreePage,
PVOID FreePageContext)
ULONG_PTR Address;
PVOID EndAddress;
PEPROCESS CurrentProcess = PsGetCurrentProcess();
-
- if (AddressSpace->Process != NULL &&
- AddressSpace->Process != CurrentProcess)
+ PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
+
+ if (Process != NULL &&
+ Process != CurrentProcess)
{
- KeAttachProcess(&AddressSpace->Process->Pcb);
+ KeAttachProcess(&Process->Pcb);
}
EndAddress = MM_ROUND_UP(MemoryArea->EndingAddress, PAGE_SIZE);
}
else
{
- BOOL Dirty = FALSE;
+ BOOLEAN Dirty = FALSE;
SWAPENTRY SwapEntry = 0;
PFN_TYPE Page = 0;
- if (MmIsPageSwapEntry(AddressSpace->Process, (PVOID)Address))
+ if (MmIsPageSwapEntry(Process, (PVOID)Address))
{
- MmDeletePageFileMapping(AddressSpace->Process, (PVOID)Address, &SwapEntry);
+ MmDeletePageFileMapping(Process, (PVOID)Address, &SwapEntry);
}
else
{
- MmDeleteVirtualMapping(AddressSpace->Process, (PVOID)Address, FALSE, &Dirty, &Page);
+ MmDeleteVirtualMapping(Process, (PVOID)Address, FALSE, &Dirty, &Page);
}
if (FreePage != NULL)
{
}
}
- if (AddressSpace->Process != NULL &&
- AddressSpace->Process != CurrentProcess)
+ if (Process != NULL &&
+ Process != CurrentProcess)
{
KeDetachProcess();
}
ParentReplace = &MemoryArea->Parent->RightChild;
}
else
- ParentReplace = &AddressSpace->MemoryAreaRoot;
+ ParentReplace = (PMEMORY_AREA*)&AddressSpace->WorkingSetExpansionLinks.Flink;
if (MemoryArea->RightChild == NULL)
{
* @remarks Lock the address space before calling this function.
*/
-NTSTATUS STDCALL
+NTSTATUS NTAPI
MmFreeMemoryAreaByPtr(
- PMADDRESS_SPACE AddressSpace,
+ PMMSUPPORT AddressSpace,
PVOID BaseAddress,
PMM_FREE_PAGE_FUNC FreePage,
PVOID FreePageContext)
BaseAddress);
if (MemoryArea == NULL)
{
- KEBUGCHECK(0);
+ KeBugCheck(MEMORY_MANAGEMENT);
return(STATUS_UNSUCCESSFUL);
}
* @remarks Lock the address space before calling this function.
*/
-NTSTATUS STDCALL
-MmCreateMemoryArea(PEPROCESS Process,
- PMADDRESS_SPACE AddressSpace,
+NTSTATUS NTAPI
+MmCreateMemoryArea(PMMSUPPORT AddressSpace,
ULONG Type,
PVOID *BaseAddress,
ULONG_PTR Length,
- ULONG Attributes,
+ ULONG Protect,
PMEMORY_AREA *Result,
BOOLEAN FixedAddress,
- BOOLEAN TopDown,
+ ULONG AllocationFlags,
PHYSICAL_ADDRESS BoundaryAddressMultiple)
{
PVOID EndAddress;
PMEMORY_AREA MemoryArea;
DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
- "*BaseAddress %p, Length %p, Attributes %x, TopDown: %x, "
+ "*BaseAddress %p, Length %p, AllocationFlags %x, "
"FixedAddress %x, Result %p)\n",
- Type, BaseAddress, *BaseAddress, Length, Attributes, TopDown,
+ Type, BaseAddress, *BaseAddress, Length, AllocationFlags,
FixedAddress, Result);
MmVerifyMemoryAreas(AddressSpace);
*BaseAddress = MmFindGap(AddressSpace,
tmpLength,
Granularity,
- TopDown != 0);
+ (AllocationFlags & MEM_TOP_DOWN) == MEM_TOP_DOWN);
if ((*BaseAddress) == 0)
{
DPRINT("No suitable gap\n");
- (ULONG_PTR) MM_ROUND_DOWN(*BaseAddress, Granularity));
*BaseAddress = MM_ROUND_DOWN(*BaseAddress, Granularity);
- if (AddressSpace->LowestAddress == (PVOID)KERNEL_BASE &&
- *BaseAddress < (PVOID)KERNEL_BASE)
+ if (!MmGetAddressSpaceOwner(AddressSpace) && *BaseAddress < MmSystemRangeStart)
{
- CHECKPOINT;
return STATUS_ACCESS_VIOLATION;
}
- if (AddressSpace->LowestAddress < (PVOID)KERNEL_BASE &&
- (ULONG_PTR)(*BaseAddress) + tmpLength > KERNEL_BASE)
+ if (MmGetAddressSpaceOwner(AddressSpace) &&
+ (ULONG_PTR)(*BaseAddress) + tmpLength > (ULONG_PTR)MmSystemRangeStart)
{
- CHECKPOINT;
return STATUS_ACCESS_VIOLATION;
}
return STATUS_CONFLICTING_ADDRESSES;
}
}
-
- MemoryArea = ExAllocatePoolWithTag(NonPagedPool, sizeof(MEMORY_AREA),
- TAG_MAREA);
+
+ //
+ // 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++];
+ }
+ else
+ {
+ //
+ // Allocate the memory area from nonpaged pool
+ //
+ MemoryArea = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(MEMORY_AREA),
+ TAG_MAREA);
+ }
+
RtlZeroMemory(MemoryArea, sizeof(MEMORY_AREA));
MemoryArea->Type = Type;
MemoryArea->StartingAddress = *BaseAddress;
MemoryArea->EndingAddress = (PVOID)((ULONG_PTR)*BaseAddress + tmpLength);
- MemoryArea->Attributes = Attributes;
- MemoryArea->LockCount = 0;
- MemoryArea->Process = Process;
+ MemoryArea->Protect = Protect;
+ MemoryArea->Flags = AllocationFlags;
+ //MemoryArea->LockCount = 0;
MemoryArea->PageOpCount = 0;
MemoryArea->DeleteInProgress = FALSE;
return STATUS_SUCCESS;
}
+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++)
+ {
+ PFN_TYPE 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);
+ }
+ }
+}
+
-VOID STDCALL
+VOID NTAPI
MmReleaseMemoryAreaIfDecommitted(PEPROCESS Process,
- PMADDRESS_SPACE AddressSpace,
+ PMMSUPPORT AddressSpace,
PVOID BaseAddress)
{
PMEMORY_AREA MemoryArea;