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
|
2014-11-10 16:26:55 +00:00
|
|
|
#include <cache/section/newmm.h>
|
2008-08-30 16:31:06 +00:00
|
|
|
#include <debug.h>
|
1998-09-05 17:33:57 +00:00
|
|
|
|
2012-02-20 20:51:18 +00:00
|
|
|
#include "ARM3/miarm.h"
|
|
|
|
|
2009-06-21 05:46:50 +00:00
|
|
|
MEMORY_AREA MiStaticMemoryAreas[MI_STATIC_MEMORY_AREAS];
|
|
|
|
ULONG MiStaticMemoryAreaCount;
|
|
|
|
|
2015-05-17 00:34:45 +00:00
|
|
|
MM_AVL_TABLE MiRosKernelVadRoot;
|
|
|
|
BOOLEAN MiRosKernelVadRootInitialized;
|
|
|
|
|
1998-09-05 17:33:57 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2008-11-29 20:47:48 +00:00
|
|
|
PMEMORY_AREA NTAPI
|
2005-01-02 19:14:52 +00:00
|
|
|
MmLocateMemoryAreaByAddress(
|
2014-10-05 06:33:34 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
2015-05-16 20:09:40 +00:00
|
|
|
PVOID Address_)
|
1998-09-05 17:33:57 +00:00
|
|
|
{
|
2015-05-17 00:35:09 +00:00
|
|
|
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;
|
1998-09-05 17:33:57 +00:00
|
|
|
|
2015-05-17 00:35:09 +00:00
|
|
|
Process = MmGetAddressSpaceOwner(AddressSpace);
|
|
|
|
Table = (Process != NULL) ? &Process->VadRoot : &MiRosKernelVadRoot;
|
2005-01-02 17:55:06 +00:00
|
|
|
|
2015-05-17 00:35:09 +00:00
|
|
|
Result = MiCheckForConflictingNode(StartVpn, StartVpn, Table, &Node);
|
|
|
|
if (Result != TableFoundNode)
|
2014-10-05 06:33:34 +00:00
|
|
|
{
|
2015-05-17 00:35:09 +00:00
|
|
|
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;
|
|
|
|
}
|
2014-10-05 06:33:34 +00:00
|
|
|
else
|
|
|
|
{
|
2015-05-17 00:35:09 +00:00
|
|
|
/* This is a section VAD. Store the MAREA here for now */
|
|
|
|
MemoryArea = (PMEMORY_AREA)Vad->u4.Banked;
|
2014-10-05 06:33:34 +00:00
|
|
|
}
|
|
|
|
}
|
2015-05-17 00:35:09 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
MemoryArea = (PMEMORY_AREA)Node;
|
|
|
|
}
|
2014-10-05 06:33:34 +00:00
|
|
|
|
2015-05-17 00:35:09 +00:00
|
|
|
return MemoryArea;
|
1998-09-05 17:33:57 +00:00
|
|
|
}
|
|
|
|
|
2015-05-17 00:34:45 +00:00
|
|
|
PMEMORY_AREA
|
|
|
|
NTAPI
|
2005-01-02 19:14:52 +00:00
|
|
|
MmLocateMemoryAreaByRegion(
|
2014-10-05 06:33:34 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
2015-05-16 20:09:40 +00:00
|
|
|
PVOID Address_,
|
2014-10-05 06:33:34 +00:00
|
|
|
ULONG_PTR Length)
|
2015-05-17 00:34:45 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
ASSERT(MemoryArea != NULL);
|
|
|
|
return MemoryArea;
|
|
|
|
}
|
|
|
|
|
2010-10-05 05:07:13 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
MiInsertVad(IN PMMVAD Vad,
|
2015-05-16 23:36:42 +00:00
|
|
|
IN PMM_AVL_TABLE VadRoot);
|
2010-10-05 05:07:13 +00:00
|
|
|
|
2010-10-18 14:25:33 +00:00
|
|
|
ULONG
|
|
|
|
NTAPI
|
|
|
|
MiMakeProtectionMask(
|
|
|
|
IN ULONG Protect
|
|
|
|
);
|
|
|
|
|
2015-05-16 23:36:42 +00:00
|
|
|
|
2005-01-02 17:55:06 +00:00
|
|
|
static VOID
|
|
|
|
MmInsertMemoryArea(
|
2014-10-05 06:33:34 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
|
|
|
PMEMORY_AREA marea)
|
2005-01-02 17:55:06 +00:00
|
|
|
{
|
2014-10-05 06:33:34 +00:00
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
|
|
|
|
2015-05-16 23:36:42 +00:00
|
|
|
marea->VadNode.u.VadFlags.Spare = 1;
|
|
|
|
marea->VadNode.u.VadFlags.Protection = MiMakeProtectionMask(marea->Protect);
|
|
|
|
|
2014-10-05 06:33:34 +00:00
|
|
|
/* Build a lame VAD if this is a user-space allocation */
|
2017-08-18 07:13:34 +00:00
|
|
|
if (marea->VadNode.EndingVpn + 1 < (ULONG_PTR)MmSystemRangeStart >> PAGE_SHIFT)
|
2014-10-05 06:33:34 +00:00
|
|
|
{
|
2015-05-17 00:35:37 +00:00
|
|
|
ASSERT(Process != NULL);
|
2015-05-16 23:36:42 +00:00
|
|
|
if (marea->Type != MEMORY_AREA_OWNED_BY_ARM3)
|
|
|
|
{
|
|
|
|
ASSERT(marea->Type == MEMORY_AREA_SECTION_VIEW || marea->Type == MEMORY_AREA_CACHE);
|
2014-10-05 06:33:34 +00:00
|
|
|
|
2015-05-16 23:36:42 +00:00
|
|
|
/* Insert the VAD */
|
|
|
|
MiLockProcessWorkingSetUnsafe(PsGetCurrentProcess(), PsGetCurrentThread());
|
|
|
|
MiInsertVad(&marea->VadNode, &Process->VadRoot);
|
|
|
|
MiUnlockProcessWorkingSetUnsafe(PsGetCurrentProcess(), PsGetCurrentThread());
|
|
|
|
marea->Vad = &marea->VadNode;
|
|
|
|
}
|
2014-10-05 06:33:34 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-05-17 00:35:37 +00:00
|
|
|
ASSERT(Process == NULL);
|
|
|
|
|
2015-05-16 23:36:42 +00:00
|
|
|
if (!MiRosKernelVadRootInitialized)
|
|
|
|
{
|
|
|
|
MiRosKernelVadRoot.BalancedRoot.u1.Parent = &MiRosKernelVadRoot.BalancedRoot;
|
2015-05-17 00:35:37 +00:00
|
|
|
MiRosKernelVadRoot.Unused = 1;
|
2015-05-16 23:36:42 +00:00
|
|
|
MiRosKernelVadRootInitialized = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Insert the VAD */
|
|
|
|
MiLockWorkingSet(PsGetCurrentThread(), &MmSystemCacheWs);
|
|
|
|
MiInsertVad(&marea->VadNode, &MiRosKernelVadRoot);
|
|
|
|
MiUnlockWorkingSet(PsGetCurrentThread(), &MmSystemCacheWs);
|
2014-10-05 06:33:34 +00:00
|
|
|
marea->Vad = NULL;
|
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
}
|
2003-05-17 15:29:50 +00:00
|
|
|
|
2015-05-17 00:35:37 +00:00
|
|
|
PVOID NTAPI
|
|
|
|
MmFindGap(
|
2014-10-05 06:33:34 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
|
|
|
ULONG_PTR Length,
|
2015-05-17 00:35:37 +00:00
|
|
|
ULONG_PTR Granularity,
|
|
|
|
BOOLEAN TopDown)
|
2003-05-17 15:29:50 +00:00
|
|
|
{
|
2015-05-17 00:35:37 +00:00
|
|
|
PEPROCESS Process;
|
|
|
|
PMM_AVL_TABLE VadRoot;
|
|
|
|
TABLE_SEARCH_RESULT Result;
|
|
|
|
PMMADDRESS_NODE Parent;
|
|
|
|
ULONG_PTR StartingAddress, HighestAddress;
|
2003-05-17 15:29:50 +00:00
|
|
|
|
2015-05-17 00:35:37 +00:00
|
|
|
Process = MmGetAddressSpaceOwner(AddressSpace);
|
|
|
|
VadRoot = Process ? &Process->VadRoot : &MiRosKernelVadRoot;
|
|
|
|
if (TopDown)
|
2012-02-03 20:59:35 +00:00
|
|
|
{
|
2015-05-17 00:35:37 +00:00
|
|
|
/* Find an address top-down */
|
|
|
|
HighestAddress = Process ? (ULONG_PTR)MM_HIGHEST_VAD_ADDRESS : (LONG_PTR)-1;
|
|
|
|
Result = MiFindEmptyAddressRangeDownTree(Length,
|
|
|
|
HighestAddress,
|
|
|
|
Granularity,
|
|
|
|
VadRoot,
|
|
|
|
&StartingAddress,
|
|
|
|
&Parent);
|
2012-02-03 20:59:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-05-17 00:35:37 +00:00
|
|
|
Result = MiFindEmptyAddressRangeInTree(Length,
|
|
|
|
Granularity,
|
|
|
|
VadRoot,
|
|
|
|
&Parent,
|
|
|
|
&StartingAddress);
|
2012-02-03 20:59:35 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
|
2015-05-17 00:35:56 +00:00
|
|
|
if (Result == TableFoundNode)
|
2013-03-13 18:13:55 +00:00
|
|
|
{
|
2015-05-17 00:35:56 +00:00
|
|
|
return NULL;
|
2013-03-13 18:13:55 +00:00
|
|
|
}
|
|
|
|
|
2015-05-17 00:35:56 +00:00
|
|
|
return (PVOID)StartingAddress;
|
2013-03-13 18:13:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
2015-05-17 00:35:56 +00:00
|
|
|
MiRemoveNode(IN PMMADDRESS_NODE Node,
|
|
|
|
IN PMM_AVL_TABLE Table);
|
2013-03-13 18:13:55 +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(
|
2014-10-05 06:33:34 +00:00
|
|
|
PMMSUPPORT AddressSpace,
|
|
|
|
PMEMORY_AREA MemoryArea,
|
|
|
|
PMM_FREE_PAGE_FUNC FreePage,
|
|
|
|
PVOID FreePageContext)
|
1998-09-05 17:33:57 +00:00
|
|
|
{
|
2014-10-05 06:33:34 +00:00
|
|
|
ULONG_PTR Address;
|
|
|
|
PVOID EndAddress;
|
2011-12-25 18:21:05 +00:00
|
|
|
|
2014-10-05 06:33:34 +00:00
|
|
|
/* Make sure we own the address space lock! */
|
|
|
|
ASSERT(CONTAINING_RECORD(AddressSpace, EPROCESS, Vm)->AddressCreationLock.Owner == KeGetCurrentThread());
|
2013-03-13 18:13:55 +00:00
|
|
|
|
|
|
|
/* Check magic */
|
|
|
|
ASSERT(MemoryArea->Magic == 'erAM');
|
|
|
|
|
2014-10-05 06:33:34 +00:00
|
|
|
if (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3)
|
|
|
|
{
|
|
|
|
PEPROCESS CurrentProcess = PsGetCurrentProcess();
|
|
|
|
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
|
|
|
|
|
|
|
if (Process != NULL &&
|
|
|
|
Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeAttachProcess(&Process->Pcb);
|
|
|
|
}
|
|
|
|
|
2015-05-16 20:10:26 +00:00
|
|
|
EndAddress = MM_ROUND_UP(MA_GetEndingAddress(MemoryArea), PAGE_SIZE);
|
2015-05-16 20:10:03 +00:00
|
|
|
for (Address = MA_GetStartingAddress(MemoryArea);
|
2014-10-05 06:33:34 +00:00
|
|
|
Address < (ULONG_PTR)EndAddress;
|
|
|
|
Address += PAGE_SIZE)
|
|
|
|
{
|
|
|
|
BOOLEAN Dirty = FALSE;
|
|
|
|
SWAPENTRY SwapEntry = 0;
|
|
|
|
PFN_NUMBER Page = 0;
|
|
|
|
|
|
|
|
if (MmIsPageSwapEntry(Process, (PVOID)Address))
|
|
|
|
{
|
2010-07-21 17:58:09 +00:00
|
|
|
MmDeletePageFileMapping(Process, (PVOID)Address, &SwapEntry);
|
2014-10-05 06:33:34 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-10-05 07:16:01 +00:00
|
|
|
MmDeleteVirtualMapping(Process, (PVOID)Address, &Dirty, &Page);
|
2014-10-05 06:33:34 +00:00
|
|
|
}
|
|
|
|
if (FreePage != NULL)
|
|
|
|
{
|
2010-07-21 17:58:09 +00:00
|
|
|
FreePage(FreePageContext, MemoryArea, (PVOID)Address,
|
|
|
|
Page, SwapEntry, (BOOLEAN)Dirty);
|
2014-10-05 06:33:34 +00:00
|
|
|
}
|
2012-02-20 20:51:18 +00:00
|
|
|
#if (_MI_PAGING_LEVELS == 2)
|
|
|
|
/* Remove page table reference */
|
2012-03-05 19:54:00 +00:00
|
|
|
ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
|
2013-11-13 11:43:21 +00:00
|
|
|
if ((SwapEntry || Page) && ((PVOID)Address < MmSystemRangeStart))
|
2012-02-20 20:51:18 +00:00
|
|
|
{
|
|
|
|
ASSERT(AddressSpace != MmGetKernelAddressSpace());
|
2013-11-24 12:51:45 +00:00
|
|
|
if (MiQueryPageTableReferences((PVOID)Address) == 0)
|
2012-02-20 20:51:18 +00:00
|
|
|
{
|
|
|
|
/* No PTE relies on this PDE. Release it */
|
2017-11-21 22:33:42 +00:00
|
|
|
KIRQL OldIrql = MiAcquirePfnLock();
|
2012-02-20 20:51:18 +00:00
|
|
|
PMMPDE PointerPde = MiAddressToPde(Address);
|
|
|
|
ASSERT(PointerPde->u.Hard.Valid == 1);
|
|
|
|
MiDeletePte(PointerPde, MiPdeToPte(PointerPde), Process, NULL);
|
|
|
|
ASSERT(PointerPde->u.Hard.Valid == 0);
|
2017-11-21 22:33:42 +00:00
|
|
|
MiReleasePfnLock(OldIrql);
|
2012-02-20 20:51:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2014-10-05 06:33:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Process != NULL &&
|
|
|
|
Process != CurrentProcess)
|
|
|
|
{
|
|
|
|
KeDetachProcess();
|
|
|
|
}
|
|
|
|
|
2015-05-16 23:36:42 +00:00
|
|
|
//if (MemoryArea->VadNode.StartingVpn < (ULONG_PTR)MmSystemRangeStart >> PAGE_SHIFT
|
2014-10-05 06:33:34 +00:00
|
|
|
if (MemoryArea->Vad)
|
|
|
|
{
|
2017-08-18 07:13:34 +00:00
|
|
|
ASSERT(MemoryArea->VadNode.EndingVpn + 1 < (ULONG_PTR)MmSystemRangeStart >> PAGE_SHIFT);
|
2014-10-05 06:33:34 +00:00
|
|
|
ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW || MemoryArea->Type == MEMORY_AREA_CACHE);
|
|
|
|
|
|
|
|
/* MmCleanProcessAddressSpace might have removed it (and this would be MmDeleteProcessAdressSpace) */
|
2015-05-16 23:36:42 +00:00
|
|
|
ASSERT(MemoryArea->VadNode.u.VadFlags.Spare != 0);
|
2014-10-05 06:33:34 +00:00
|
|
|
if (((PMMVAD)MemoryArea->Vad)->u.VadFlags.Spare == 1)
|
|
|
|
{
|
2015-05-16 23:36:42 +00:00
|
|
|
MiRemoveNode((PMMADDRESS_NODE)&MemoryArea->VadNode, &Process->VadRoot);
|
2014-10-05 06:33:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MemoryArea->Vad = NULL;
|
|
|
|
}
|
2015-05-16 23:36:42 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
MiRemoveNode((PMMADDRESS_NODE)&MemoryArea->VadNode, &MiRosKernelVadRoot);
|
|
|
|
}
|
2010-07-21 17:58:09 +00:00
|
|
|
}
|
2005-01-02 17:55:06 +00:00
|
|
|
|
2016-08-09 07:28:02 +00:00
|
|
|
#if DBG
|
|
|
|
MemoryArea->Magic = 'daeD';
|
|
|
|
#endif
|
2014-10-05 06:33:34 +00:00
|
|
|
ExFreePoolWithTag(MemoryArea, TAG_MAREA);
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2018-08-16 13:10:24 +00:00
|
|
|
DPRINT("MmFreeMemoryArea() succeeded\n");
|
2004-04-10 22:36:07 +00:00
|
|
|
|
2014-10-05 06:33:34 +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,
|
2005-11-13 17:28:24 +00:00
|
|
|
ULONG AllocationFlags,
|
2013-11-26 21:38:02 +00:00
|
|
|
ULONG Granularity)
|
1998-09-05 17:33:57 +00:00
|
|
|
{
|
2014-10-05 06:33:34 +00:00
|
|
|
ULONG_PTR tmpLength;
|
|
|
|
PMEMORY_AREA MemoryArea;
|
|
|
|
ULONG_PTR EndingAddress;
|
|
|
|
|
|
|
|
DPRINT("MmCreateMemoryArea(Type 0x%lx, BaseAddress %p, "
|
|
|
|
"*BaseAddress %p, Length %p, AllocationFlags %x, "
|
2015-05-16 21:30:28 +00:00
|
|
|
"Result %p)\n",
|
2014-10-05 06:33:34 +00:00
|
|
|
Type, BaseAddress, *BaseAddress, Length, AllocationFlags,
|
2015-05-16 21:30:28 +00:00
|
|
|
Result);
|
2014-10-05 06:33:34 +00:00
|
|
|
|
2015-05-17 00:35:56 +00:00
|
|
|
/* Is this a static memory area? */
|
2015-05-16 21:30:52 +00:00
|
|
|
if (Type & MEMORY_AREA_STATIC)
|
|
|
|
{
|
2015-05-17 00:35:56 +00:00
|
|
|
/* Use the static array instead of the pool */
|
2015-05-16 21:30:52 +00:00
|
|
|
ASSERT(MiStaticMemoryAreaCount < MI_STATIC_MEMORY_AREAS);
|
|
|
|
MemoryArea = &MiStaticMemoryAreas[MiStaticMemoryAreaCount++];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-05-17 00:35:56 +00:00
|
|
|
/* Allocate the memory area from nonpaged pool */
|
2015-05-16 21:30:52 +00:00
|
|
|
MemoryArea = ExAllocatePoolWithTag(NonPagedPool,
|
|
|
|
sizeof(MEMORY_AREA),
|
|
|
|
TAG_MAREA);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!MemoryArea)
|
|
|
|
{
|
|
|
|
DPRINT1("Not enough memory.\n");
|
|
|
|
return STATUS_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlZeroMemory(MemoryArea, sizeof(MEMORY_AREA));
|
|
|
|
MemoryArea->Type = Type & ~MEMORY_AREA_STATIC;
|
|
|
|
MemoryArea->Protect = Protect;
|
|
|
|
MemoryArea->Flags = AllocationFlags;
|
|
|
|
MemoryArea->Magic = 'erAM';
|
|
|
|
MemoryArea->DeleteInProgress = FALSE;
|
|
|
|
|
2015-05-16 21:30:28 +00:00
|
|
|
if (*BaseAddress == 0)
|
2014-10-05 06:33:34 +00:00
|
|
|
{
|
|
|
|
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");
|
2015-05-16 21:30:52 +00:00
|
|
|
if (!(Type & MEMORY_AREA_STATIC)) ExFreePoolWithTag(MemoryArea, TAG_MAREA);
|
2014-10-05 06:33:34 +00:00
|
|
|
return STATUS_NO_MEMORY;
|
|
|
|
}
|
2015-05-16 21:30:52 +00:00
|
|
|
|
2017-08-18 07:13:34 +00:00
|
|
|
MemoryArea->VadNode.StartingVpn = (ULONG_PTR)*BaseAddress >> PAGE_SHIFT;
|
|
|
|
MemoryArea->VadNode.EndingVpn = ((ULONG_PTR)*BaseAddress + tmpLength - 1) >> PAGE_SHIFT;
|
2015-05-16 21:30:52 +00:00
|
|
|
MmInsertMemoryArea(AddressSpace, MemoryArea);
|
2014-10-05 06:33:34 +00:00
|
|
|
}
|
|
|
|
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)
|
|
|
|
{
|
2015-05-16 21:30:52 +00:00
|
|
|
ASSERT(FALSE);
|
|
|
|
if (!(Type & MEMORY_AREA_STATIC)) ExFreePoolWithTag(MemoryArea, TAG_MAREA);
|
2014-10-05 06:33:34 +00:00
|
|
|
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");
|
2015-05-16 21:30:52 +00:00
|
|
|
if (!(Type & MEMORY_AREA_STATIC)) ExFreePoolWithTag(MemoryArea, TAG_MAREA);
|
2014-10-05 06:33:34 +00:00
|
|
|
return STATUS_ACCESS_VIOLATION;
|
|
|
|
}
|
|
|
|
|
2015-05-17 00:35:47 +00:00
|
|
|
/* No need to check ARM3 owned memory areas, the range MUST be free */
|
|
|
|
if (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3)
|
2015-05-17 00:34:45 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2014-10-05 06:33:34 +00:00
|
|
|
}
|
2009-09-02 13:02:30 +00:00
|
|
|
|
2017-08-18 07:13:34 +00:00
|
|
|
MemoryArea->VadNode.StartingVpn = (ULONG_PTR)*BaseAddress >> PAGE_SHIFT;
|
|
|
|
MemoryArea->VadNode.EndingVpn = ((ULONG_PTR)*BaseAddress + tmpLength - 1) >> PAGE_SHIFT;
|
2015-05-16 21:30:52 +00:00
|
|
|
MmInsertMemoryArea(AddressSpace, MemoryArea);
|
2014-10-05 06:33:34 +00:00
|
|
|
}
|
2009-09-02 13:02:30 +00:00
|
|
|
|
2014-10-05 06:33:34 +00:00
|
|
|
*Result = MemoryArea;
|
2005-01-02 17:55:06 +00:00
|
|
|
|
2014-10-05 06:33:34 +00:00
|
|
|
DPRINT("MmCreateMemoryArea() succeeded (%p)\n", *BaseAddress);
|
|
|
|
return STATUS_SUCCESS;
|
1998-09-05 17:33:57 +00:00
|
|
|
}
|
2004-10-01 20:26:05 +00:00
|
|
|
|
2015-05-17 00:34:59 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
MiRosCleanupMemoryArea(
|
|
|
|
PEPROCESS Process,
|
|
|
|
PMMVAD Vad)
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2017-06-08 20:34:47 +00:00
|
|
|
Status = MiRosUnmapViewOfSection(Process, BaseAddress, Process->ProcessExiting);
|
2015-05-17 00:34:59 +00:00
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
2008-03-13 13:17:57 +00:00
|
|
|
|
[NTOSKRNL]: This is kind of embarssing, but after doing a local grep for some of cgutman and zekflop's changes (respectively the patch that had added MmDeleteProcessPageDirectory, and the mshtml fix patch), I fell upon a .patch file. It included 3 memory-leak-fixing patches from richard that had been sent to me during his last days -- which, had I paid attention, would've fixed the MSHTML bug and the memory leaks months ago! I've tried my best to now re-integrate a portion of the patch (the other two portions deal with freeing the loader block, and freeing .INIT sections, and I will commit them later) with the current state of trunk. Some things that patch did, no longer seem to work, and I've commented where appropriate. But in general it does seem to dereference/delete some PTEs that had been left behind before (such as deleted TEBs, and deleted VA mappings). It no longer seems to be able to delete the root PDE nor the shared data page however (this worked in the original patch's timeframe). Zekflop, tkreuzer, please take a look. I hope this will set us on a better path!
svn path=/trunk/; revision=55666
2012-02-17 07:07:47 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
MmDeleteProcessAddressSpace2(IN PEPROCESS Process);
|
|
|
|
|
2010-10-05 15:55:52 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
MmDeleteProcessAddressSpace(PEPROCESS Process)
|
2004-10-01 20:26:05 +00:00
|
|
|
{
|
2018-01-01 14:24:05 +00:00
|
|
|
#ifndef _M_AMD64
|
2015-09-05 14:39:40 +00:00
|
|
|
KIRQL OldIrql;
|
2014-10-05 06:33:34 +00:00
|
|
|
PVOID Address;
|
2018-01-01 14:24:05 +00:00
|
|
|
#endif
|
2005-01-29 03:15:05 +00:00
|
|
|
|
2014-10-05 06:33:34 +00:00
|
|
|
DPRINT("MmDeleteProcessAddressSpace(Process %p (%s))\n", Process,
|
|
|
|
Process->ImageFileName);
|
2005-01-02 17:55:06 +00:00
|
|
|
|
2012-02-03 20:59:35 +00:00
|
|
|
#ifndef _M_AMD64
|
2015-09-05 14:39:40 +00:00
|
|
|
OldIrql = MiAcquireExpansionLock();
|
2014-10-05 06:33:34 +00:00
|
|
|
RemoveEntryList(&Process->MmProcessLinks);
|
2015-09-05 14:39:40 +00:00
|
|
|
MiReleaseExpansionLock(OldIrql);
|
2012-02-03 20:59:35 +00:00
|
|
|
#endif
|
2014-10-05 06:33:34 +00:00
|
|
|
MmLockAddressSpace(&Process->Vm);
|
|
|
|
|
2015-05-17 00:35:23 +00:00
|
|
|
/* There should not be any memory areas left! */
|
|
|
|
ASSERT(Process->Vm.WorkingSetExpansionLinks.Flink == NULL);
|
2013-03-13 18:13:55 +00:00
|
|
|
|
2012-02-21 00:32:24 +00:00
|
|
|
#if (_MI_PAGING_LEVELS == 2)
|
|
|
|
{
|
|
|
|
KIRQL OldIrql;
|
|
|
|
PMMPDE pointerPde;
|
|
|
|
/* Attach to Process */
|
|
|
|
KeAttachProcess(&Process->Pcb);
|
2013-03-13 18:13:55 +00:00
|
|
|
|
2012-02-21 00:32:24 +00:00
|
|
|
/* Acquire PFN lock */
|
2017-11-21 22:33:42 +00:00
|
|
|
OldIrql = MiAcquirePfnLock();
|
2013-03-13 18:13:55 +00:00
|
|
|
|
2013-11-13 11:43:21 +00:00
|
|
|
for (Address = MI_LOWEST_VAD_ADDRESS;
|
2014-10-05 06:33:34 +00:00
|
|
|
Address < MM_HIGHEST_VAD_ADDRESS;
|
|
|
|
Address =(PVOID)((ULONG_PTR)Address + (PAGE_SIZE * PTE_COUNT)))
|
2012-02-21 00:32:24 +00:00
|
|
|
{
|
|
|
|
/* At this point all references should be dead */
|
2013-11-24 12:51:45 +00:00
|
|
|
if (MiQueryPageTableReferences(Address) != 0)
|
2013-11-13 11:43:21 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Process %p, Address %p, UsedPageTableEntries %lu\n",
|
|
|
|
Process,
|
|
|
|
Address,
|
2013-11-24 12:51:45 +00:00
|
|
|
MiQueryPageTableReferences(Address));
|
|
|
|
ASSERT(MiQueryPageTableReferences(Address) == 0);
|
2013-11-13 11:43:21 +00:00
|
|
|
}
|
2015-05-17 00:34:59 +00:00
|
|
|
|
2012-02-21 00:32:24 +00:00
|
|
|
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 */
|
2013-11-13 11:43:21 +00:00
|
|
|
if (pointerPde->u.Hard.Valid)
|
2012-02-21 00:32:24 +00:00
|
|
|
MiDeletePte(pointerPde, MiPdeToPte(pointerPde), Process, NULL);
|
|
|
|
ASSERT(pointerPde->u.Hard.Valid == 0);
|
|
|
|
}
|
2015-05-17 00:34:59 +00:00
|
|
|
|
2012-02-21 00:32:24 +00:00
|
|
|
/* Release lock */
|
2017-11-21 22:33:42 +00:00
|
|
|
MiReleasePfnLock(OldIrql);
|
2013-03-13 18:13:55 +00:00
|
|
|
|
2012-02-21 00:32:24 +00:00
|
|
|
/* Detach */
|
|
|
|
KeDetachProcess();
|
|
|
|
}
|
|
|
|
#endif
|
2010-10-05 15:55:52 +00:00
|
|
|
|
2014-10-05 06:33:34 +00:00
|
|
|
MmUnlockAddressSpace(&Process->Vm);
|
2010-10-05 15:55:52 +00:00
|
|
|
|
2014-10-05 06:33:34 +00:00
|
|
|
DPRINT("Finished MmDeleteProcessAddressSpace()\n");
|
|
|
|
MmDeleteProcessAddressSpace2(Process);
|
|
|
|
return(STATUS_SUCCESS);
|
2004-10-01 20:26:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|