[RSHELL]
[reactos.git] / ntoskrnl / mm / marea.c
index 6e21439..759be7a 100644 (file)
 
 #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;
 
@@ -370,13 +373,14 @@ MmInsertMemoryArea(
    PMEMORY_AREA Node;
    PMEMORY_AREA PreviousNode;
    ULONG Depth = 0;
+   PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
 
    /* Build a lame VAD if this is a user-space allocation */
    if ((marea->EndingAddress < MmSystemRangeStart) && (marea->Type != MEMORY_AREA_OWNED_BY_ARM3))
    {
        PMMVAD Vad;
 
-       ASSERT(marea->Type == MEMORY_AREA_VIRTUAL_MEMORY || marea->Type == MEMORY_AREA_SECTION_VIEW);
+       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));
@@ -397,7 +401,9 @@ MmInsertMemoryArea(
        Vad->u.VadFlags.Spare = 1;
        Vad->u.VadFlags.PrivateMemory = 1;
        Vad->u.VadFlags.Protection = MiMakeProtectionMask(marea->Protect);
-       MiInsertVad(Vad, MmGetAddressSpaceOwner(AddressSpace));
+
+       /* Insert the VAD */
+       MiInsertVad(Vad, Process);
        marea->Vad = Vad;
    }
    else
@@ -670,6 +676,100 @@ 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
  *
@@ -688,6 +788,12 @@ IN PMM_AVL_TABLE Table);
  *
  * @remarks Lock the address space before calling this function.
  */
+VOID
+NTAPI
+MiDeletePte(IN PMMPTE PointerPte,
+            IN PVOID VirtualAddress,
+            IN PEPROCESS CurrentProcess,
+            IN PMMPTE PrototypePte);
 
 NTSTATUS NTAPI
 MmFreeMemoryArea(
@@ -700,6 +806,12 @@ MmFreeMemoryArea(
    ULONG_PTR Address;
    PVOID EndAddress;
 
+   /* Make sure we own the address space lock! */
+   ASSERT(CONTAINING_RECORD(AddressSpace, EPROCESS, Vm)->AddressCreationLock.Owner == KeGetCurrentThread());
+
+    /* Check magic */
+    ASSERT(MemoryArea->Magic == 'erAM');
+
    if (MemoryArea->Type != MEMORY_AREA_OWNED_BY_ARM3)
    {
        PEPROCESS CurrentProcess = PsGetCurrentProcess();
@@ -733,6 +845,24 @@ MmFreeMemoryArea(
                 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 &&
@@ -744,7 +874,7 @@ MmFreeMemoryArea(
        if (MemoryArea->Vad)
        {
            ASSERT(MemoryArea->EndingAddress < MmSystemRangeStart);
-           ASSERT(MemoryArea->Type == MEMORY_AREA_VIRTUAL_MEMORY || MemoryArea->Type == MEMORY_AREA_SECTION_VIEW);
+           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);
@@ -758,9 +888,6 @@ MmFreeMemoryArea(
        }
     }
 
-    /* There must be no page ops in progress */
-    ASSERT(MemoryArea->PageOpCount == 0);
-
    /* Remove the tree item. */
    {
       if (MemoryArea->Parent != NULL)
@@ -857,10 +984,8 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
                    PMEMORY_AREA *Result,
                    BOOLEAN FixedAddress,
                    ULONG AllocationFlags,
-                   PHYSICAL_ADDRESS BoundaryAddressMultiple)
+                   ULONG Granularity)
 {
-   PVOID EndAddress;
-   ULONG Granularity;
    ULONG_PTR tmpLength;
    PMEMORY_AREA MemoryArea;
 
@@ -870,7 +995,6 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
           Type, BaseAddress, *BaseAddress, Length, AllocationFlags,
           FixedAddress, Result);
 
-   Granularity = (MEMORY_AREA_VIRTUAL_MEMORY == Type ? MM_VIRTMEM_GRANULARITY : PAGE_SIZE);
    if ((*BaseAddress) == 0 && !FixedAddress)
    {
       tmpLength = (ULONG_PTR)MM_ROUND_UP(Length, Granularity);
@@ -903,12 +1027,6 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
          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)
@@ -940,7 +1058,11 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
                                            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;
@@ -949,7 +1071,7 @@ MmCreateMemoryArea(PMMSUPPORT AddressSpace,
    MemoryArea->Protect = Protect;
    MemoryArea->Flags = AllocationFlags;
    //MemoryArea->LockCount = 0;
-   MemoryArea->PageOpCount = 0;
+   MemoryArea->Magic = 'erAM';
    MemoryArea->DeleteInProgress = FALSE;
 
    MmInsertMemoryArea(AddressSpace, MemoryArea);
@@ -994,6 +1116,10 @@ MmMapMemoryArea(PVOID BaseAddress,
    }
 }
 
+VOID
+NTAPI
+MmDeleteProcessAddressSpace2(IN PEPROCESS Process);
+
 NTSTATUS
 NTAPI
 MmDeleteProcessAddressSpace(PEPROCESS Process)
@@ -1001,7 +1127,7 @@ MmDeleteProcessAddressSpace(PEPROCESS Process)
    PVOID Address;
    PMEMORY_AREA MemoryArea;
 
-   DPRINT("MmDeleteProcessAddressSpace(Process %x (%s))\n", Process,
+   DPRINT("MmDeleteProcessAddressSpace(Process %p (%s))\n", Process,
           Process->ImageFileName);
 
 #ifndef _M_AMD64
@@ -1020,8 +1146,11 @@ MmDeleteProcessAddressSpace(PEPROCESS Process)
              MmLockAddressSpace(&Process->Vm);
              break;
 
-         case MEMORY_AREA_VIRTUAL_MEMORY:
-             MmFreeVirtualMemory(Process, MemoryArea);
+         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:
@@ -1036,11 +1165,48 @@ MmDeleteProcessAddressSpace(PEPROCESS Process)
       }
    }
 
-   MmDeleteProcessPageDirectory(Process);
+#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);
 }