#include <ntoskrnl.h>
#define NDEBUG
+#include "../cache/section/newmm.h"
#include <debug.h>
+#include "ARM3/miarm.h"
+
MEMORY_AREA MiStaticMemoryAreas[MI_STATIC_MEMORY_AREAS];
ULONG MiStaticMemoryAreaCount;
-/* #define VALIDATE_MEMORY_AREAS */
-
/* FUNCTIONS *****************************************************************/
/**
return Node;
}
-#ifdef VALIDATE_MEMORY_AREAS
-static VOID MmVerifyMemoryAreas(PMMSUPPORT AddressSpace)
-{
- PMEMORY_AREA Node;
-
- ASSERT(AddressSpace != NULL);
-
- /* Special case for empty tree. */
- if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
- return;
-
- /* Traverse the tree from left to right. */
- 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 == NULL);
- ASSERT(Node->EndingAddress >= Node->StartingAddress);
- }
-}
-#else
-#define MmVerifyMemoryAreas(x)
-#endif
-
-VOID NTAPI
-MmDumpMemoryAreas(PMMSUPPORT AddressSpace)
-{
- PMEMORY_AREA Node;
-
- DbgPrint("MmDumpMemoryAreas()\n");
-
- /* Special case for empty tree. */
- if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
- return;
-
- /* Traverse the tree from left to right. */
- for (Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
- Node != NULL;
- Node = MmIterateNextNode(Node))
- {
- DbgPrint("Start %p End %p Protect %x Flags %x\n",
- Node->StartingAddress, Node->EndingAddress,
- Node->Protect, Node->Flags);
- }
-
- DbgPrint("Finished MmDumpMemoryAreas()\n");
-}
-
PMEMORY_AREA NTAPI
MmLocateMemoryAreaByAddress(
PMMSUPPORT AddressSpace,
DPRINT("MmLocateMemoryAreaByAddress(AddressSpace %p, Address %p)\n",
AddressSpace, Address);
- MmVerifyMemoryAreas(AddressSpace);
-
while (Node != NULL)
{
if (Address < Node->StartingAddress)
PMEMORY_AREA Node;
PVOID Extent = (PVOID)((ULONG_PTR)Address + Length);
- MmVerifyMemoryAreas(AddressSpace);
-
/* Special case for empty tree. */
if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
return NULL;
}
}
+VOID
+NTAPI
+MiInsertVad(IN PMMVAD Vad,
+IN PEPROCESS Process);
+
+ULONG
+NTAPI
+MiMakeProtectionMask(
+ IN ULONG Protect
+);
+
static VOID
MmInsertMemoryArea(
PMMSUPPORT AddressSpace,
PMEMORY_AREA Node;
PMEMORY_AREA PreviousNode;
ULONG Depth = 0;
+ PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
- MmVerifyMemoryAreas(AddressSpace);
+ /* Build a lame VAD if this is a user-space allocation */
+ if ((marea->EndingAddress < MmSystemRangeStart) && (marea->Type != MEMORY_AREA_OWNED_BY_ARM3))
+ {
+ PMMVAD Vad;
+
+ ASSERT(marea->Type == MEMORY_AREA_SECTION_VIEW || marea->Type == MEMORY_AREA_CACHE);
+ Vad = ExAllocatePoolWithTag(NonPagedPool, sizeof(MMVAD), TAG_MVAD);
+ ASSERT(Vad);
+ RtlZeroMemory(Vad, sizeof(MMVAD));
+ Vad->StartingVpn = PAGE_ROUND_DOWN(marea->StartingAddress) >> PAGE_SHIFT;
+ /*
+ * For some strange reason, it is perfectly valid to create a MAREA from 0x1000 to... 0x1000.
+ * In a normal OS/Memory Manager, this would be retarded, but ReactOS allows this (how it works
+ * I don't even want to know).
+ */
+ if (marea->EndingAddress != marea->StartingAddress)
+ {
+ Vad->EndingVpn = PAGE_ROUND_DOWN((ULONG_PTR)marea->EndingAddress - 1) >> PAGE_SHIFT;
+ }
+ else
+ {
+ Vad->EndingVpn = Vad->StartingVpn;
+ }
+ Vad->u.VadFlags.Spare = 1;
+ Vad->u.VadFlags.PrivateMemory = 1;
+ Vad->u.VadFlags.Protection = MiMakeProtectionMask(marea->Protect);
+
+ /* Insert the VAD */
+ MiInsertVad(Vad, Process);
+ marea->Vad = Vad;
+ }
+ else
+ {
+ marea->Vad = NULL;
+ }
if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
{
ULONG_PTR Length,
ULONG_PTR Granularity)
{
- 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;
- PMEMORY_AREA PreviousNode;
+ ULONG_PTR LowestAddress, HighestAddress, Candidate;
+ PMEMORY_AREA Root, Node;
- MmVerifyMemoryAreas(AddressSpace);
-
- DPRINT("LowestAddress: %p HighestAddress: %p\n",
- LowestAddress, HighestAddress);
-
- AlignedAddress = MM_ROUND_UP(LowestAddress, Granularity);
-
- /* Special case for empty tree. */
- if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
- {
- if ((ULONG_PTR)HighestAddress - (ULONG_PTR)AlignedAddress >= Length)
- {
- DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
- return AlignedAddress;
- }
- DPRINT("MmFindGapBottomUp: 0\n");
- return 0;
- }
+ /* Get the margins of the address space */
+ if (MmGetAddressSpaceOwner(AddressSpace) != NULL)
+ {
+ LowestAddress = (ULONG_PTR)MM_LOWEST_USER_ADDRESS;
+ HighestAddress = (ULONG_PTR)MmHighestUserAddress;
+ }
+ else
+ {
+ LowestAddress = (ULONG_PTR)MmSystemRangeStart;
+ HighestAddress = MAXULONG_PTR;
+ }
- /* Go to the node with lowest address in the tree. */
- FirstNode = Node = MmIterateFirstNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
+ /* Start with the lowest address */
+ Candidate = LowestAddress;
- /* Traverse the tree from left to right. */
- PreviousNode = Node;
- for (;;)
- {
- Node = MmIterateNextNode(Node);
- if (Node == NULL)
- break;
+ /* Check for overflow */
+ if ((Candidate + Length) < Candidate) return NULL;
- AlignedAddress = MM_ROUND_UP(PreviousNode->EndingAddress, Granularity);
- if (Node->StartingAddress > AlignedAddress &&
- (ULONG_PTR)Node->StartingAddress - (ULONG_PTR)AlignedAddress >= Length)
- {
- DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
- return AlignedAddress;
- }
+ /* Get the root of the address space tree */
+ Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
- PreviousNode = Node;
- }
+ /* Go to the node with lowest address in the tree. */
+ Node = Root ? MmIterateFirstNode(Root) : NULL;
+ while (Node && ((ULONG_PTR)Node->EndingAddress < LowestAddress))
+ {
+ Node = MmIterateNextNode(Node);
+ }
- /* Check if there is enough space after the last memory area. */
- AlignedAddress = MM_ROUND_UP(PreviousNode->EndingAddress, Granularity);
- if ((ULONG_PTR)HighestAddress > (ULONG_PTR)AlignedAddress &&
- (ULONG_PTR)HighestAddress - (ULONG_PTR)AlignedAddress >= Length)
- {
- DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
- return AlignedAddress;
- }
+ /* Traverse the tree from low to high addresses */
+ while (Node && ((ULONG_PTR)Node->EndingAddress < HighestAddress))
+ {
+ /* Check if the memory area fits before the current node */
+ if ((ULONG_PTR)Node->StartingAddress >= (Candidate + Length))
+ {
+ DPRINT("MmFindGapBottomUp: %p\n", Candidate);
+ ASSERT(Candidate >= LowestAddress);
+ return (PVOID)Candidate;
+ }
+
+ /* Calculate next possible adress above this node */
+ Candidate = ALIGN_UP_BY((ULONG_PTR)Node->EndingAddress, Granularity);
+
+ /* Check for overflow */
+ if ((Candidate + Length) < (ULONG_PTR)Node->EndingAddress) return NULL;
+
+ /* Go to the next higher node */
+ Node = MmIterateNextNode(Node);
+ }
- /* Check if there is enough space before the first memory area. */
- AlignedAddress = MM_ROUND_UP(LowestAddress, Granularity);
- if (FirstNode->StartingAddress > AlignedAddress &&
- (ULONG_PTR)FirstNode->StartingAddress - (ULONG_PTR)AlignedAddress >= Length)
- {
- DPRINT("MmFindGapBottomUp: %p\n", AlignedAddress);
- return AlignedAddress;
- }
+ /* Check if there is enough space after the last memory area. */
+ if ((Candidate + Length) <= HighestAddress)
+ {
+ DPRINT("MmFindGapBottomUp: %p\n", Candidate);
+ ASSERT(Candidate >= LowestAddress);
+ return (PVOID)Candidate;
+ }
- DPRINT("MmFindGapBottomUp: 0\n");
- return 0;
+ DPRINT("MmFindGapBottomUp: 0\n");
+ return NULL;
}
ULONG_PTR Length,
ULONG_PTR Granularity)
{
- 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",
- LowestAddress, HighestAddress);
-
- AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)HighestAddress - Length + 1, Granularity);
+ ULONG_PTR LowestAddress, HighestAddress, Candidate;
+ PMEMORY_AREA Root, Node;
- /* Check for overflow. */
- if (AlignedAddress > HighestAddress)
- return NULL;
-
- /* Special case for empty tree. */
- if (AddressSpace->WorkingSetExpansionLinks.Flink == NULL)
- {
- if (AlignedAddress >= LowestAddress)
- {
- DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
- return AlignedAddress;
- }
- DPRINT("MmFindGapTopDown: 0\n");
- return 0;
- }
-
- /* Go to the node with highest address in the tree. */
- Node = MmIterateLastNode((PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink);
-
- /* Check if there is enough space after the last memory area. */
- if (Node->EndingAddress <= AlignedAddress)
- {
- DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
- return AlignedAddress;
- }
-
- /* Traverse the tree from left to right. */
- PreviousNode = Node;
- for (;;)
- {
- Node = MmIteratePrevNode(Node);
- if (Node == NULL)
- break;
+ /* Get the margins of the address space */
+ if (MmGetAddressSpaceOwner(AddressSpace) != NULL)
+ {
+ LowestAddress = (ULONG_PTR)MM_LOWEST_USER_ADDRESS;
+ HighestAddress = (ULONG_PTR)MmHighestUserAddress;
+ }
+ else
+ {
+ LowestAddress = (ULONG_PTR)MmSystemRangeStart;
+ HighestAddress = MAXULONG_PTR;
+ }
- AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)PreviousNode->StartingAddress - Length + 1, Granularity);
+ /* Calculate the highest candidate */
+ Candidate = ALIGN_DOWN_BY(HighestAddress + 1 - Length, Granularity);
- /* Check for overflow. */
- if (AlignedAddress > PreviousNode->StartingAddress)
- return NULL;
+ /* Check for overflow. */
+ if (Candidate > HighestAddress) return NULL;
- if (Node->EndingAddress <= AlignedAddress)
- {
- DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
- return AlignedAddress;
- }
+ /* Get the root of the address space tree */
+ Root = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
- PreviousNode = Node;
- }
+ /* Go to the node with highest address in the tree. */
+ Node = Root ? MmIterateLastNode(Root) : NULL;
+ while (Node && ((ULONG_PTR)Node->StartingAddress > HighestAddress))
+ {
+ Node = MmIteratePrevNode(Node);
+ }
- AlignedAddress = MM_ROUND_DOWN((ULONG_PTR)PreviousNode->StartingAddress - Length + 1, Granularity);
+ /* Traverse the tree from high to low addresses */
+ while (Node && ((ULONG_PTR)Node->StartingAddress > LowestAddress))
+ {
+ /* Check if the memory area fits after the current node */
+ if ((ULONG_PTR)Node->EndingAddress <= Candidate)
+ {
+ DPRINT("MmFindGapTopDown: %p\n", Candidate);
+ return (PVOID)Candidate;
+ }
+
+ /* Calculate next possible adress below this node */
+ Candidate = ALIGN_DOWN_BY((ULONG_PTR)Node->StartingAddress - Length,
+ Granularity);
+
+ /* Check for overflow. */
+ if (Candidate > (ULONG_PTR)Node->StartingAddress)
+ return NULL;
- /* Check for overflow. */
- if (AlignedAddress > PreviousNode->StartingAddress)
- return NULL;
+ /* Go to the next lower node */
+ Node = MmIteratePrevNode(Node);
+ }
- if (AlignedAddress >= LowestAddress)
- {
- DPRINT("MmFindGapTopDown: %p\n", AlignedAddress);
- return AlignedAddress;
- }
+ /* Check if the last candidate is inside the given range */
+ if (Candidate >= LowestAddress)
+ {
+ DPRINT("MmFindGapTopDown: %p\n", Candidate);
+ return (PVOID)Candidate;
+ }
- DPRINT("MmFindGapTopDown: 0\n");
- return 0;
+ DPRINT("MmFindGapTopDown: 0\n");
+ return NULL;
}
PVOID HighestAddress = MmGetAddressSpaceOwner(AddressSpace) ?
(PVOID)((ULONG_PTR)MmSystemRangeStart - 1) : (PVOID)MAXULONG_PTR;
- MmVerifyMemoryAreas(AddressSpace);
-
Address = MM_ROUND_DOWN(Address, PAGE_SIZE);
if (LowestAddress < MmSystemRangeStart)
}
}
+VOID
+NTAPI
+MiRemoveNode(IN PMMADDRESS_NODE Node,
+IN PMM_AVL_TABLE Table);
+
+#if DBG
+
+static
+VOID
+MiRosCheckMemoryAreasRecursive(
+ PMEMORY_AREA Node)
+{
+ /* Check if the allocation is ok */
+ ExpCheckPoolAllocation(Node, NonPagedPool, 'ERAM');
+
+ /* Check some fields */
+ ASSERT(Node->Magic == 'erAM');
+ ASSERT(PAGE_ALIGN(Node->StartingAddress) == Node->StartingAddress);
+ ASSERT(Node->EndingAddress != NULL);
+ ASSERT(PAGE_ALIGN(Node->EndingAddress) == Node->EndingAddress);
+ ASSERT((ULONG_PTR)Node->StartingAddress < (ULONG_PTR)Node->EndingAddress);
+ ASSERT((Node->Type == 0) ||
+ (Node->Type == MEMORY_AREA_CACHE) ||
+ // (Node->Type == MEMORY_AREA_CACHE_SEGMENT) ||
+ (Node->Type == MEMORY_AREA_SECTION_VIEW) ||
+ (Node->Type == MEMORY_AREA_OWNED_BY_ARM3) ||
+ (Node->Type == (MEMORY_AREA_OWNED_BY_ARM3 | MEMORY_AREA_STATIC)));
+
+ /* Recursively check children */
+ if (Node->LeftChild != NULL)
+ MiRosCheckMemoryAreasRecursive(Node->LeftChild);
+ if (Node->RightChild != NULL)
+ MiRosCheckMemoryAreasRecursive(Node->RightChild);
+}
+
+VOID
+NTAPI
+MiRosCheckMemoryAreas(
+ PMMSUPPORT AddressSpace)
+{
+ PMEMORY_AREA RootNode;
+ PEPROCESS AddressSpaceOwner;
+ BOOLEAN NeedReleaseLock;
+
+ NeedReleaseLock = FALSE;
+
+ /* Get the address space owner */
+ AddressSpaceOwner = CONTAINING_RECORD(AddressSpace, EPROCESS, Vm);
+
+ /* Check if we already own the address space lock */
+ if (AddressSpaceOwner->AddressCreationLock.Owner != KeGetCurrentThread())
+ {
+ /* We must own it! */
+ MmLockAddressSpace(AddressSpace);
+ NeedReleaseLock = TRUE;
+ }
+
+ /* Check all memory areas */
+ RootNode = (PMEMORY_AREA)AddressSpace->WorkingSetExpansionLinks.Flink;
+ MiRosCheckMemoryAreasRecursive(RootNode);
+
+ /* Release the lock, if we acquired it */
+ if (NeedReleaseLock)
+ {
+ MmUnlockAddressSpace(AddressSpace);
+ }
+}
+
+extern KGUARDED_MUTEX PspActiveProcessMutex;
+
+VOID
+NTAPI
+MiCheckAllProcessMemoryAreas(VOID)
+{
+ PEPROCESS Process;
+ PLIST_ENTRY Entry;
+
+ /* Acquire the Active Process Lock */
+ KeAcquireGuardedMutex(&PspActiveProcessMutex);
+
+ /* Loop the process list */
+ Entry = PsActiveProcessHead.Flink;
+ while (Entry != &PsActiveProcessHead)
+ {
+ /* Get the process */
+ Process = CONTAINING_RECORD(Entry, EPROCESS, ActiveProcessLinks);
+
+ /* Check memory areas */
+ MiRosCheckMemoryAreas(&Process->Vm);
+
+ Entry = Entry->Flink;
+ }
+
+ /* Release the lock */
+ KeReleaseGuardedMutex(&PspActiveProcessMutex);
+}
+
+#endif
/**
* @name MmFreeMemoryArea
*
* @remarks Lock the address space before calling this function.
*/
+VOID
+NTAPI
+MiDeletePte(IN PMMPTE PointerPte,
+ IN PVOID VirtualAddress,
+ IN PEPROCESS CurrentProcess,
+ IN PMMPTE PrototypePte);
NTSTATUS NTAPI
MmFreeMemoryArea(
PMEMORY_AREA *ParentReplace;
ULONG_PTR Address;
PVOID EndAddress;
- 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)
- {
- if (MemoryArea->Type == MEMORY_AREA_IO_MAPPING)
- {
- MmRawDeleteVirtualMapping((PVOID)Address);
- }
- else
- {
- BOOLEAN Dirty = FALSE;
- SWAPENTRY SwapEntry = 0;
- PFN_NUMBER Page = 0;
+ /* Make sure we own the address space lock! */
+ ASSERT(CONTAINING_RECORD(AddressSpace, EPROCESS, Vm)->AddressCreationLock.Owner == KeGetCurrentThread());
- 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);
- }
- }
- }
+ /* Check magic */
+ ASSERT(MemoryArea->Magic == 'erAM');
- if (Process != NULL &&
- Process != CurrentProcess)
+ if (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3)
{
- KeDetachProcess();
- }
+ 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 (_MI_PAGING_LEVELS == 2)
+ /* Remove page table reference */
+ ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
+ if ((SwapEntry || Page) && ((PVOID)Address < MmSystemRangeStart))
+ {
+ ASSERT(AddressSpace != MmGetKernelAddressSpace());
+ if (MiQueryPageTableReferences((PVOID)Address) == 0)
+ {
+ /* No PTE relies on this PDE. Release it */
+ KIRQL OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ PMMPDE PointerPde = MiAddressToPde(Address);
+ ASSERT(PointerPde->u.Hard.Valid == 1);
+ MiDeletePte(PointerPde, MiPdeToPte(PointerPde), Process, NULL);
+ ASSERT(PointerPde->u.Hard.Valid == 0);
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ }
+ }
+#endif
+ }
+
+ if (Process != NULL &&
+ Process != CurrentProcess)
+ {
+ KeDetachProcess();
+ }
+
+ if (MemoryArea->Vad)
+ {
+ ASSERT(MemoryArea->EndingAddress < MmSystemRangeStart);
+ ASSERT(MemoryArea->Type == MEMORY_AREA_SECTION_VIEW || MemoryArea->Type == MEMORY_AREA_CACHE);
+
+ /* MmCleanProcessAddressSpace might have removed it (and this would be MmDeleteProcessAdressSpace) */
+ ASSERT(((PMMVAD)MemoryArea->Vad)->u.VadFlags.Spare != 0);
+ if (((PMMVAD)MemoryArea->Vad)->u.VadFlags.Spare == 1)
+ {
+ MiRemoveNode(MemoryArea->Vad, &Process->VadRoot);
+ }
+
+ ExFreePoolWithTag(MemoryArea->Vad, TAG_MVAD);
+ MemoryArea->Vad = NULL;
+ }
+ }
/* Remove the tree item. */
{
return STATUS_SUCCESS;
}
-/**
- * @name MmFreeMemoryAreaByPtr
- *
- * Free an existing memory area given a pointer inside it.
- *
- * @param AddressSpace
- * Address space to free the area from.
- * @param BaseAddress
- * Address in the 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
- *
- * @see MmFreeMemoryArea
- *
- * @todo Should we require the BaseAddress to be really the starting
- * address of the memory area or is the current relaxed check
- * (BaseAddress can point anywhere in the memory area) acceptable?
- *
- * @remarks Lock the address space before calling this function.
- */
-
-NTSTATUS NTAPI
-MmFreeMemoryAreaByPtr(
- PMMSUPPORT AddressSpace,
- PVOID BaseAddress,
- PMM_FREE_PAGE_FUNC FreePage,
- PVOID FreePageContext)
-{
- PMEMORY_AREA MemoryArea;
-
- DPRINT("MmFreeMemoryArea(AddressSpace %p, BaseAddress %p, "
- "FreePageContext %p)\n", AddressSpace, BaseAddress,
- FreePageContext);
-
- MmVerifyMemoryAreas(AddressSpace);
-
- MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace,
- BaseAddress);
- if (MemoryArea == NULL)
- {
- KeBugCheck(MEMORY_MANAGEMENT);
- return(STATUS_UNSUCCESSFUL);
- }
-
- return MmFreeMemoryArea(AddressSpace, MemoryArea, FreePage, FreePageContext);
-}
-
/**
* @name MmCreateMemoryArea
*
PMEMORY_AREA *Result,
BOOLEAN FixedAddress,
ULONG AllocationFlags,
- PHYSICAL_ADDRESS BoundaryAddressMultiple)
+ ULONG Granularity)
{
- PVOID EndAddress;
- ULONG Granularity;
- ULONG tmpLength;
+ ULONG_PTR tmpLength;
PMEMORY_AREA MemoryArea;
- DPRINT("MmCreateMemoryArea(Type %d, BaseAddress %p, "
+ DPRINT("MmCreateMemoryArea(Type 0x%lx, BaseAddress %p, "
"*BaseAddress %p, Length %p, AllocationFlags %x, "
"FixedAddress %x, Result %p)\n",
Type, BaseAddress, *BaseAddress, Length, AllocationFlags,
FixedAddress, Result);
- MmVerifyMemoryAreas(AddressSpace);
-
- Granularity = (MEMORY_AREA_VIRTUAL_MEMORY == Type ? MM_VIRTMEM_GRANULARITY : PAGE_SIZE);
if ((*BaseAddress) == 0 && !FixedAddress)
{
- tmpLength = PAGE_ROUND_UP(Length);
+ tmpLength = (ULONG_PTR)MM_ROUND_UP(Length, Granularity);
*BaseAddress = MmFindGap(AddressSpace,
tmpLength,
Granularity,
{
tmpLength = Length + ((ULONG_PTR) *BaseAddress
- (ULONG_PTR) MM_ROUND_DOWN(*BaseAddress, Granularity));
+ tmpLength = (ULONG_PTR)MM_ROUND_UP(tmpLength, Granularity);
*BaseAddress = MM_ROUND_DOWN(*BaseAddress, Granularity);
if (!MmGetAddressSpaceOwner(AddressSpace) && *BaseAddress < MmSystemRangeStart)
if (MmGetAddressSpaceOwner(AddressSpace) &&
(ULONG_PTR)(*BaseAddress) + tmpLength > (ULONG_PTR)MmSystemRangeStart)
{
+ DPRINT("Memory area for user mode address space exceeds MmSystemRangeStart\n");
return STATUS_ACCESS_VIOLATION;
}
- if (BoundaryAddressMultiple.QuadPart != 0)
- {
- EndAddress = ((char*)(*BaseAddress)) + tmpLength-1;
- ASSERT(((ULONG_PTR)*BaseAddress/BoundaryAddressMultiple.QuadPart) == ((DWORD_PTR)EndAddress/BoundaryAddressMultiple.QuadPart));
- }
-
if (MmLocateMemoryAreaByRegion(AddressSpace,
*BaseAddress,
tmpLength) != NULL)
return STATUS_CONFLICTING_ADDRESSES;
}
}
-
+
//
// Is this a static memory area?
//
TAG_MAREA);
}
- if (!MemoryArea) return STATUS_NO_MEMORY;
+ if (!MemoryArea)
+ {
+ DPRINT1("Not enough memory.\n");
+ return STATUS_NO_MEMORY;
+ }
RtlZeroMemory(MemoryArea, sizeof(MEMORY_AREA));
MemoryArea->Type = Type;
MemoryArea->Protect = Protect;
MemoryArea->Flags = AllocationFlags;
//MemoryArea->LockCount = 0;
- MemoryArea->PageOpCount = 0;
+ MemoryArea->Magic = 'erAM';
MemoryArea->DeleteInProgress = FALSE;
MmInsertMemoryArea(AddressSpace, MemoryArea);
VOID NTAPI
MmMapMemoryArea(PVOID BaseAddress,
- ULONG Length,
+ SIZE_T Length,
ULONG Consumer,
ULONG Protection)
{
ULONG i;
NTSTATUS Status;
+ ASSERT(((ULONG_PTR)BaseAddress % PAGE_SIZE) == 0);
+
for (i = 0; i < PAGE_ROUND_UP(Length) / PAGE_SIZE; i++)
{
PFN_NUMBER Page;
}
}
+VOID
+NTAPI
+MmDeleteProcessAddressSpace2(IN PEPROCESS Process);
-VOID NTAPI
-MmReleaseMemoryAreaIfDecommitted(PEPROCESS Process,
- PMMSUPPORT AddressSpace,
- PVOID BaseAddress)
+NTSTATUS
+NTAPI
+MmDeleteProcessAddressSpace(PEPROCESS Process)
{
+ PVOID Address;
PMEMORY_AREA MemoryArea;
- PLIST_ENTRY Entry;
- PMM_REGION Region;
- BOOLEAN Reserved;
- MmVerifyMemoryAreas(AddressSpace);
+ DPRINT("MmDeleteProcessAddressSpace(Process %p (%s))\n", Process,
+ Process->ImageFileName);
- MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
- if (MemoryArea != NULL)
- {
- Entry = MemoryArea->Data.VirtualMemoryData.RegionListHead.Flink;
- Reserved = TRUE;
- while (Reserved && Entry != &MemoryArea->Data.VirtualMemoryData.RegionListHead)
- {
- Region = CONTAINING_RECORD(Entry, MM_REGION, RegionListEntry);
- Reserved = (MEM_RESERVE == Region->Type);
- Entry = Entry->Flink;
- }
+#ifndef _M_AMD64
+ RemoveEntryList(&Process->MmProcessLinks);
+#endif
+ MmLockAddressSpace(&Process->Vm);
- if (Reserved)
+ while ((MemoryArea = (PMEMORY_AREA)Process->Vm.WorkingSetExpansionLinks.Flink) != NULL)
+ {
+ switch (MemoryArea->Type)
{
- MmFreeVirtualMemory(Process, MemoryArea);
+ case MEMORY_AREA_SECTION_VIEW:
+ Address = (PVOID)MemoryArea->StartingAddress;
+ MmUnlockAddressSpace(&Process->Vm);
+ MmUnmapViewOfSection(Process, Address);
+ MmLockAddressSpace(&Process->Vm);
+ break;
+
+ case MEMORY_AREA_CACHE:
+ Address = (PVOID)MemoryArea->StartingAddress;
+ MmUnlockAddressSpace(&Process->Vm);
+ MmUnmapViewOfCacheSegment(&Process->Vm, Address);
+ MmLockAddressSpace(&Process->Vm);
+ break;
+
+ case MEMORY_AREA_OWNED_BY_ARM3:
+ MmFreeMemoryArea(&Process->Vm,
+ MemoryArea,
+ NULL,
+ NULL);
+ break;
+
+ default:
+ KeBugCheck(MEMORY_MANAGEMENT);
}
}
+
+#if (_MI_PAGING_LEVELS == 2)
+ {
+ KIRQL OldIrql;
+ PMMPDE pointerPde;
+ /* Attach to Process */
+ KeAttachProcess(&Process->Pcb);
+
+ /* Acquire PFN lock */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ for (Address = MI_LOWEST_VAD_ADDRESS;
+ Address < MM_HIGHEST_VAD_ADDRESS;
+ Address =(PVOID)((ULONG_PTR)Address + (PAGE_SIZE * PTE_COUNT)))
+ {
+ /* At this point all references should be dead */
+ if (MiQueryPageTableReferences(Address) != 0)
+ {
+ DPRINT1("Process %p, Address %p, UsedPageTableEntries %lu\n",
+ Process,
+ Address,
+ MiQueryPageTableReferences(Address));
+ ASSERT(MiQueryPageTableReferences(Address) == 0);
+ }
+ pointerPde = MiAddressToPde(Address);
+ /* Unlike in ARM3, we don't necesarrily free the PDE page as soon as reference reaches 0,
+ * so we must clean up a bit when process closes */
+ if (pointerPde->u.Hard.Valid)
+ MiDeletePte(pointerPde, MiPdeToPte(pointerPde), Process, NULL);
+ ASSERT(pointerPde->u.Hard.Valid == 0);
+ }
+ /* Release lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* Detach */
+ KeDetachProcess();
+ }
+#endif
+
+ MmUnlockAddressSpace(&Process->Vm);
+
+ DPRINT("Finished MmReleaseMmInfo()\n");
+ MmDeleteProcessAddressSpace2(Process);
+ return(STATUS_SUCCESS);
}
/* EOF */