[NTOSKRNL]: Fix broken way we were creating prototype PTEs, which was only supporting...
authorAlex Ionescu <aionescu@gmail.com>
Fri, 24 Aug 2012 06:08:20 +0000 (06:08 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Fri, 24 Aug 2012 06:08:20 +0000 (06:08 +0000)
[NTOSKRNL]: Add support (macros) for subsection PTEs.

svn path=/trunk/; revision=57148

reactos/ntoskrnl/mm/ARM3/miarm.h
reactos/ntoskrnl/mm/ARM3/mminit.c
reactos/ntoskrnl/mm/ARM3/pagfault.c

index c99b0a6..344f5c6 100644 (file)
@@ -266,7 +266,19 @@ extern const ULONG MmProtectToValue[32];
 //
 #define MiProtoPteToPte(x)                  \
     (PMMPTE)((ULONG_PTR)MmPagedPoolStart +  \
-             (((x)->u.Proto.ProtoAddressHigh << 7) | (x)->u.Proto.ProtoAddressLow))
+             (((x)->u.Proto.ProtoAddressHigh << 9) | (x)->u.Proto.ProtoAddressLow << 2))
+
+//
+// Decodes a Prototype PTE into the underlying PTE
+//
+#define MiSubsectionPteToSubsection(x)                              \
+    ((x)->u.Subsect.WhichPool == PagedPool) ?                       \
+        (PMMPTE)((ULONG_PTR)MmSubsectionBase +                      \
+                 (((x)->u.Subsect.SubsectionAddressHigh << 7) |     \
+                   (x)->u.Subsect.SubsectionAddressLow << 3)) :     \
+        (PMMPTE)((ULONG_PTR)MmNonPagedPoolEnd -                     \
+                (((x)->u.Subsect.SubsectionAddressHigh << 7) |      \
+                  (x)->u.Subsect.SubsectionAddressLow << 3))
 #endif
 
 //
@@ -631,7 +643,6 @@ extern PVOID MmSystemCacheStart;
 extern PVOID MmSystemCacheEnd;
 extern MMSUPPORT MmSystemCacheWs;
 extern SIZE_T MmAllocatedNonPagedPool;
-extern ULONG_PTR MmSubsectionBase;
 extern ULONG MmSpecialPoolTag;
 extern PVOID MmHyperSpaceEnd;
 extern PMMWSL MmSystemCacheWorkingSetList;
@@ -694,6 +705,7 @@ extern MM_AVL_TABLE MmSectionBasedRoot;
 extern KGUARDED_MUTEX MmSectionBasedMutex;
 extern PVOID MmHighSectionBase;
 extern SIZE_T MmSystemLockPagesCount;
+extern ULONG_PTR MmSubsectionBase;
 
 BOOLEAN
 FORCEINLINE
@@ -875,15 +887,58 @@ MI_MAKE_PROTOTYPE_PTE(IN PMMPTE NewPte,
 
     /*
      * Prototype PTEs are only valid in paged pool by design, this little trick
-     * lets us only use 28 bits for the adress of the PTE
+     * lets us only use 30 bits for the adress of the PTE, as long as the area
+     * stays 1024MB At most.
      */
     Offset = (ULONG_PTR)PointerPte - (ULONG_PTR)MmPagedPoolStart;
 
-    /* 7 bits go in the "low", and the other 21 bits go in the "high" */
-    NewPte->u.Proto.ProtoAddressLow = Offset & 0x7F;
-    NewPte->u.Proto.ProtoAddressHigh = (Offset & 0xFFFFFF80) >> 7;
-    ASSERT(MiProtoPteToPte(NewPte) == PointerPte);
+    /*
+     * 7 bits go in the "low" (but we assume the bottom 2 are zero)
+     * and the other 21 bits go in the "high"
+     */
+    NewPte->u.Proto.ProtoAddressLow = (Offset & 0x1FC) >> 2;
+    NewPte->u.Proto.ProtoAddressHigh = (Offset & 0x3FFFFE00) >> 9;
 }
+
+//
+// Builds a Subsection PTE for the address of the Segment
+//
+FORCEINLINE
+VOID
+MI_MAKE_SUBSECTION_PTE(IN PMMPTE NewPte,
+                       IN PVOID Segment)
+{
+    ULONG_PTR Offset;
+
+    /* Mark this as a prototype */
+    NewPte->u.Long = 0;
+    NewPte->u.Subsect.Prototype = 1;
+
+    /*
+     * Segments are only valid either in nonpaged pool. We store the 20 bit
+     * difference either from the top or bottom of nonpaged pool, giving a
+     * maximum of 128MB to each delta, meaning nonpaged pool cannot exceed
+     * 256MB.
+     */
+    if ((ULONG_PTR)Segment < ((ULONG_PTR)MmSubsectionBase + (128 * _1MB)))
+    {
+        Offset = (ULONG_PTR)Segment - (ULONG_PTR)MmSubsectionBase;
+        NewPte->u.Subsect.WhichPool = PagedPool;
+    }
+    else
+    {
+        Offset = (ULONG_PTR)MmNonPagedPoolEnd - (ULONG_PTR)Segment;
+        NewPte->u.Subsect.WhichPool = NonPagedPool;
+    }
+
+    /*
+     * 4 bits go in the "low" (but we assume the bottom 3 are zero)
+     * and the other 20 bits go in the "high"
+     */
+    NewPte->u.Subsect.SubsectionAddressLow = (Offset & 0x78) >> 3;
+    NewPte->u.Subsect.SubsectionAddressHigh = (Offset & 0xFFFFF80) >> 7;
+}
+
 #endif
 
 //
index 3d4e1b0..8b7e87e 100644 (file)
@@ -2004,6 +2004,11 @@ MmArmInitSystem(IN ULONG Phase,
     PVOID Bitmap;
     PPHYSICAL_MEMORY_RUN Run;
     PFN_NUMBER PageCount;
+#if DBG
+    ULONG j;
+    PMMPTE PointerPte, TestPte;
+    MMPTE TempPte;
+#endif
 
     /* Dump memory descriptors */
     if (MiDbgEnableMdDump) MiDbgDumpMemoryDescriptors();
@@ -2063,10 +2068,44 @@ MmArmInitSystem(IN ULONG Phase,
 
         /* Initialize session space address layout */
         MiInitializeSessionSpaceLayout();
-        
+
         /* Set the based section highest address */
         MmHighSectionBase = (PVOID)((ULONG_PTR)MmHighestUserAddress - 0x800000);
 
+#if DBG
+        /* The subection PTE format depends on things being 8-byte aligned */
+        ASSERT((sizeof(CONTROL_AREA) % 8) == 0);
+        ASSERT((sizeof(SUBSECTION) % 8) == 0);
+
+        /* Prototype PTEs are assumed to be in paged pool, so check if the math works */
+        PointerPte = (PMMPTE)MmPagedPoolStart;
+        MI_MAKE_PROTOTYPE_PTE(&TempPte, PointerPte);
+        TestPte = MiProtoPteToPte(&TempPte);
+        ASSERT(PointerPte == TestPte);
+
+        /* Try the last nonpaged pool address */
+        PointerPte = (PMMPTE)MI_NONPAGED_POOL_END;
+        MI_MAKE_PROTOTYPE_PTE(&TempPte, PointerPte);
+        TestPte = MiProtoPteToPte(&TempPte);
+        ASSERT(PointerPte == TestPte);
+
+        /* Try a bunch of random addresses near the end of the address space */
+        PointerPte = (PMMPTE)0xFFFC8000;
+        for (j = 0; j < 20; j += 1)
+        {
+            MI_MAKE_PROTOTYPE_PTE(&TempPte, PointerPte);
+            TestPte = MiProtoPteToPte(&TempPte);
+            ASSERT(PointerPte == TestPte);
+            PointerPte++;
+        }
+
+        /* Subsection PTEs are always in nonpaged pool, pick a random address to try */
+        PointerPte = (PMMPTE)0xFFAACBB8;
+        MI_MAKE_SUBSECTION_PTE(&TempPte, PointerPte);
+        TestPte = MiSubsectionPteToSubsection(&TempPte);
+        ASSERT(PointerPte == TestPte);
+#endif
+
         /* Loop all 8 standby lists */
         for (i = 0; i < 8; i++)
         {
index 96e884e..b8995cf 100644 (file)
@@ -1742,18 +1742,15 @@ UserFault:
     {
         /* Get the protection code and check if this is a proto PTE */
         ProtectionCode = TempPte.u.Soft.Protection;
-        DPRINT1("Code: %lx\n", ProtectionCode);
         if (TempPte.u.Soft.Prototype)
         {
             /* Do we need to go find the real PTE? */
-            DPRINT1("Soft: %lx\n", TempPte.u.Soft.PageFileHigh);
             if (TempPte.u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
             {
                 /* Get the prototype pte and VAD for it */
                 ProtoPte = MiCheckVirtualAddress(Address,
                                                  &ProtectionCode,
                                                  &Vad);
-                DPRINT1("Address: %p ProtoP %p Code: %lx Vad: %p\n", Address, ProtoPte, ProtectionCode, Vad);
                 if (!ProtoPte)
                 {
                     ASSERT(KeGetCurrentIrql() <= APC_LEVEL);