[NTOS]: Attempt to hackfix MiGetPageProtection to support the case seen in OllyDBG.
authorSir Richard <sir_richard@svn.reactos.org>
Sat, 5 May 2012 19:26:21 +0000 (19:26 +0000)
committerSir Richard <sir_richard@svn.reactos.org>
Sat, 5 May 2012 19:26:21 +0000 (19:26 +0000)
[NTOS]: Implement Case C of NtFreeVirtualMemory, which is sometimes seen in some heap logs. The hard part is figuring out the right amount of committed/decommitted pages. Only supports 2-level paging for now as the algorithm is already messy enough.

svn path=/trunk/; revision=56515

reactos/ntoskrnl/mm/ARM3/virtual.c

index c90c1be..fcee901 100644 (file)
@@ -28,6 +28,168 @@ MiProtectVirtualMemory(IN PEPROCESS Process,
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
+ULONG
+NTAPI
+MiCalculatePageCommitment(IN ULONG_PTR StartingAddress,
+                          IN ULONG_PTR EndingAddress,
+                          IN PMMVAD Vad,
+                          IN PEPROCESS Process)
+{
+    PMMPTE PointerPte, LastPte, PointerPde;
+    ULONG CommittedPages;
+
+    /* Compute starting and ending PTE and PDE addresses */
+    PointerPde = MiAddressToPde(StartingAddress);
+    PointerPte = MiAddressToPte(StartingAddress);
+    LastPte = MiAddressToPte(EndingAddress);
+
+    /* Handle commited pages first */
+    if (Vad->u.VadFlags.MemCommit == 1)
+    {
+        /* This is a committed VAD, so Assume the whole range is committed */
+        CommittedPages = BYTES_TO_PAGES(EndingAddress - StartingAddress);
+
+        /* Is the PDE demand-zero? */
+        PointerPde = MiAddressToPte(PointerPte);
+        if (PointerPde->u.Long != 0)
+        {
+            /* It is not. Is it valid? */
+            if (PointerPde->u.Hard.Valid == 0)
+            {
+                /* Fault it in */
+                PointerPte = MiPteToAddress(PointerPde);
+                MiMakeSystemAddressValid(PointerPte, Process);
+            }
+        }
+        else
+        {
+            /* It is, skip it and move to the next PDE, unless we're done */
+            PointerPde++;
+            PointerPte = MiPteToAddress(PointerPde);
+            if (PointerPte > LastPte) return CommittedPages;
+        }
+
+        /* Now loop all the PTEs in the range */
+        while (PointerPte <= LastPte)
+        {
+            /* Have we crossed a PDE boundary? */
+            if (MiIsPteOnPdeBoundary(PointerPte))
+            {
+                /* Is this PDE demand zero? */
+                PointerPde = MiAddressToPte(PointerPte);
+                if (PointerPde->u.Long != 0)
+                {
+                    /* It isn't -- is it valid? */
+                    if (PointerPde->u.Hard.Valid == 0)
+                    {
+                        /* Nope, fault it in */
+                        PointerPte = MiPteToAddress(PointerPde);
+                        MiMakeSystemAddressValid(PointerPte, Process);
+                    }
+                }
+                else
+                {
+                    /* It is, skip it and move to the next PDE */
+                    PointerPde++;
+                    PointerPte = MiPteToAddress(PointerPde);
+                    continue;
+                }
+            }
+
+            /* Is this PTE demand zero? */
+            if (PointerPte->u.Long != 0)
+            {
+                /* It isn't -- is it a decommited, invalid, or faulted PTE? */
+                if ((PointerPte->u.Soft.Protection == MM_DECOMMIT) &&
+                    (PointerPte->u.Hard.Valid == 0) &&
+                    ((PointerPte->u.Soft.Prototype == 0) ||
+                     (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)))
+                {
+                    /* It is, so remove it from the count of commited pages */
+                    CommittedPages--;
+                }
+            }
+
+            /* Move to the next PTE */
+            PointerPte++;
+        }
+
+        /* Return how many committed pages there still are */
+        return CommittedPages;
+    }
+
+    /* This is a non-commited VAD, so assume none of it is committed */
+    CommittedPages = 0;
+
+    /* Is the PDE demand-zero? */
+    PointerPde = MiAddressToPte(PointerPte);
+    if (PointerPde->u.Long != 0)
+    {
+        /* It isn't -- is it invalid? */
+        if (PointerPde->u.Hard.Valid == 0)
+        {
+            /* It is, so page it in */
+            PointerPte = MiPteToAddress(PointerPde);
+            MiMakeSystemAddressValid(PointerPte, Process);
+        }
+    }
+    else
+    {
+        /* It is, so skip it and move to the next PDE */
+        PointerPde++;
+        PointerPte = MiPteToAddress(PointerPde);
+        if (PointerPte > LastPte) return CommittedPages;
+    }
+
+    /* Loop all the PTEs in this PDE */
+    while (PointerPte <= LastPte)
+    {
+        /* Have we crossed a PDE boundary? */
+        if (MiIsPteOnPdeBoundary(PointerPte))
+        {
+            /* Is this new PDE demand-zero? */
+            PointerPde = MiAddressToPte(PointerPte);
+            if (PointerPde->u.Long != 0)
+            {
+                /* It isn't. Is it valid? */
+                if (PointerPde->u.Hard.Valid == 0)
+                {
+                    /* It isn't, so make it valid */
+                    PointerPte = MiPteToAddress(PointerPde);
+                    MiMakeSystemAddressValid(PointerPte, Process);
+                }
+            }
+            else
+            {
+                /* It is, so skip it and move to the next one */
+                PointerPde++;
+                PointerPte = MiPteToAddress(PointerPde);
+                continue;
+            }
+        }
+
+        /* Is this PTE demand-zero? */
+        if (PointerPte->u.Long != 0)
+        {
+            /* Nope. Is it a valid, non-decommited, non-paged out PTE? */
+            if ((PointerPte->u.Soft.Protection != MM_DECOMMIT) ||
+                (PointerPte->u.Hard.Valid == 1) ||
+                ((PointerPte->u.Soft.Prototype == 1) &&
+                 (PointerPte->u.Soft.PageFileHigh != MI_PTE_LOOKUP_NEEDED)))
+            {
+                /* It is! So we'll treat this as a committed page */
+                CommittedPages++;
+            }
+        }
+
+        /* Move to the next PTE */
+        PointerPte++;
+    }
+
+    /* Return how many committed pages we found in this VAD */
+    return CommittedPages;
+}
+
 ULONG
 NTAPI
 MiMakeSystemAddressValid(IN PVOID PageTableVirtualAddress,
@@ -1118,18 +1280,19 @@ MiGetPageProtection(IN PMMPTE PointerPte)
 
     /* If we get here, the PTE is valid, so look up the page in PFN database */
     Pfn = MiGetPfnEntry(TempPte.u.Hard.PageFrameNumber);
-
     if (!Pfn->u3.e1.PrototypePte)
     {
         /* Return protection of the original pte */
+        ASSERT(Pfn->u4.AweAllocation == 0);
         return MmProtectToValue[Pfn->OriginalPte.u.Soft.Protection];
     }
 
-    /* This is hardware PTE */
-    UNIMPLEMENTED;
-    ASSERT(FALSE);
-
-    return PAGE_NOACCESS;
+    /* This is software PTE */
+    DPRINT1("Prototype PTE: %lx %p\n", TempPte.u.Hard.PageFrameNumber, Pfn);
+    DPRINT1("VA: %p\n", MiPteToAddress(&TempPte));
+    DPRINT1("Mask: %lx\n", TempPte.u.Soft.Protection);
+    DPRINT1("Mask2: %lx\n", Pfn->OriginalPte.u.Soft.Protection);
+    return MmProtectToValue[TempPte.u.Soft.Protection];
 }
 
 ULONG
@@ -4049,11 +4212,13 @@ NtFreeVirtualMemory(IN HANDLE ProcessHandle,
                     // and then change the ending address of the VAD to be a bit
                     // smaller.
                     //
-                    // NOT YET IMPLEMENTED IN ARM3.
-                    //
-                    DPRINT1("Case C not handled\n");
-                    Status = STATUS_FREE_VM_NOT_AT_BASE;
-                    goto FailPath;
+                    MiLockWorkingSet(CurrentThread, AddressSpace);
+                    CommitReduction = MiCalculatePageCommitment(StartingAddress,
+                                                                EndingAddress,
+                                                                Vad,
+                                                                Process);
+                    Vad->u.VadFlags.CommitCharge -= CommitReduction;
+                    Vad->EndingVpn = ((ULONG_PTR)StartingAddress - 1) >> PAGE_SHIFT;
                 }
                 else
                 {