[NTOS]: Learn to build User PTEs as well, with MI_MAKE_HARDWARE_PTE_USER.
authorSir Richard <sir_richard@svn.reactos.org>
Thu, 22 Jul 2010 02:20:27 +0000 (02:20 +0000)
committerSir Richard <sir_richard@svn.reactos.org>
Thu, 22 Jul 2010 02:20:27 +0000 (02:20 +0000)
[NTOS]: MI_MAKE_HARDWARE_PTE becomes MI_MAKE_HARDWARE_PTE_KERNEL, since it assumed this. MI_MAKE_HARDWARE_PTE is now a "generic" you can use when you don't know what the PTE should be. It uses MiDetermineUserGlobalMask to set the right bits.
[NTOS]: Add two more helpers: MI_IS_PAGE_TABLE_ADDRESS and MI_IS_SYSTEM_PAGE_TABLE_ADDDRESS. One is in the symbols, the other I made up to make things clearer.
[NTOS]: MiResolveDemandZeroFault now knnows how to resolve user-demand-zero-faults.
[NTOS]: Implement MiZeroPfn to do the actual zeroing during user-demand-zero-faults (also later for VAD faults).

svn path=/trunk/; revision=48175

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

index fb6de0e..e3e8899 100644 (file)
@@ -193,6 +193,12 @@ MmProtectToPteMask[32] =
 #define MI_IS_SESSION_PTE(Pte) \
     ((((PMMPTE)Pte) >= MiSessionBasePte) && (((PMMPTE)Pte) < MiSessionLastPte))
 
+#define MI_IS_PAGE_TABLE_ADDRESS(Address) \
+    (((PVOID)(Address) >= (PVOID)PTE_BASE) && ((PVOID)(Address) <= (PVOID)PTE_TOP))
+
+#define MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address) \
+    (((Address) >= (PVOID)MiAddressToPte(MmSystemRangeStart)) && ((Address) <= (PVOID)PTE_TOP))
+
 //
 // Corresponds to MMPTE_SOFTWARE.Protection
 //
@@ -469,25 +475,93 @@ extern PFN_NUMBER MmSystemPageDirectory[PD_COUNT];
 #define MI_PFN_TO_PFNENTRY(x)     (&MmPfnDatabase[1][x])
 #define MI_PFNENTRY_TO_PFN(x)     (x - MmPfnDatabase[1])
 
+//
+// Figures out the hardware bits for a PTE
+//
+ULONG
+FORCEINLINE
+MiDetermineUserGlobalPteMask(IN PMMPTE PointerPte)
+{
+    MMPTE TempPte;
+    
+    /* Start fresh */
+    TempPte.u.Long = 0;
+    
+    /* Make it valid and accessed */
+    TempPte.u.Hard.Valid = TRUE;
+    TempPte.u.Hard.Accessed = TRUE;
+    
+    /* Is this for user-mode? */
+    if ((PointerPte <= MiHighestUserPte) ||
+        ((PointerPte >= MiAddressToPde(NULL)) && (PointerPte <= MiHighestUserPde)))
+    {
+        /* Set the owner bit */
+        TempPte.u.Hard.Owner = TRUE;
+    }
+    
+    /* FIXME: We should also set the global bit */
+    
+    /* Return the protection */
+    return TempPte.u.Long;
+}
+
 //
 // Creates a valid kernel PTE with the given protection
 //
 FORCEINLINE
 VOID
+MI_MAKE_HARDWARE_PTE_KERNEL(IN PMMPTE NewPte,
+                            IN PMMPTE MappingPte,
+                            IN ULONG ProtectionMask,
+                            IN PFN_NUMBER PageFrameNumber)
+{
+    /* Only valid for kernel, non-session PTEs */
+    ASSERT(MappingPte > MiHighestUserPte);
+    ASSERT(!MI_IS_SESSION_PTE(MappingPte));
+    ASSERT((MappingPte < (PMMPTE)PDE_BASE) || (MappingPte > (PMMPTE)PDE_TOP));
+    
+    /* Start fresh */
+    *NewPte = ValidKernelPte;
+    
+    /* Set the protection and page */
+    NewPte->u.Hard.PageFrameNumber = PageFrameNumber;
+    NewPte->u.Long |= MmProtectToPteMask[ProtectionMask];
+}
+
+//
+// Creates a valid PTE with the given protection
+//
+FORCEINLINE
+VOID
 MI_MAKE_HARDWARE_PTE(IN PMMPTE NewPte,
                      IN PMMPTE MappingPte,
                      IN ULONG ProtectionMask,
                      IN PFN_NUMBER PageFrameNumber)
+{
+    /* Set the protection and page */
+    NewPte->u.Long = MiDetermineUserGlobalPteMask(MappingPte);
+    NewPte->u.Long |= MmProtectToPteMask[ProtectionMask];
+    NewPte->u.Hard.PageFrameNumber = PageFrameNumber;
+}
+
+//
+// Creates a valid user PTE with the given protection
+//
+FORCEINLINE
+VOID
+MI_MAKE_HARDWARE_PTE_USER(IN PMMPTE NewPte,
+                          IN PMMPTE MappingPte,
+                          IN ULONG ProtectionMask,
+                          IN PFN_NUMBER PageFrameNumber)
 {
     /* Only valid for kernel, non-session PTEs */
-    ASSERT(MappingPte > MiHighestUserPte);
-    ASSERT(!MI_IS_SESSION_PTE(MappingPte));
-    ASSERT((MappingPte < (PMMPTE)PDE_BASE) || (MappingPte > (PMMPTE)PDE_TOP));
+    ASSERT(MappingPte <= MiHighestUserPte);
     
     /* Start fresh */
     *NewPte = ValidKernelPte;
     
     /* Set the protection and page */
+    NewPte->u.Hard.Owner = TRUE;
     NewPte->u.Hard.PageFrameNumber = PageFrameNumber;
     NewPte->u.Long |= MmProtectToPteMask[ProtectionMask];
 }
index ad85641..eeb82a7 100644 (file)
@@ -34,8 +34,7 @@ MiCheckPdeForPagedPool(IN PVOID Address)
     //
     // Check if this is a fault while trying to access the page table itself
     //
-    if ((Address >= (PVOID)MiAddressToPte(MmSystemRangeStart)) &&
-        (Address < (PVOID)PTE_TOP))
+    if (MI_IS_SYSTEM_PAGE_TABLE_ADDRESS(Address))
     {
         //
         // Send a hint to the page fault handler that this is only a valid fault
@@ -84,6 +83,52 @@ MiCheckPdeForPagedPool(IN PVOID Address)
     return Status;
 }
 
+VOID
+NTAPI
+MiZeroPfn(IN PFN_NUMBER PageFrameNumber)
+{
+    PMMPTE ZeroPte;
+    MMPTE TempPte;
+    PMMPFN Pfn1;
+    PVOID ZeroAddress;
+    
+    /* Get the PFN for this page */
+    Pfn1 = MiGetPfnEntry(PageFrameNumber);
+    ASSERT(Pfn1);
+        
+    /* Grab a system PTE we can use to zero the page */
+    ZeroPte = MiReserveSystemPtes(1, SystemPteSpace);
+    ASSERT(ZeroPte);
+    
+    /* Initialize the PTE for it */
+    TempPte = ValidKernelPte;
+    TempPte.u.Hard.PageFrameNumber = PageFrameNumber;
+
+    /* Setup caching */
+    if (Pfn1->u3.e1.CacheAttribute == MiWriteCombined)
+    {
+        /* Write combining, no caching */
+        MI_PAGE_DISABLE_CACHE(&TempPte);
+        MI_PAGE_WRITE_COMBINED(&TempPte);
+    }
+    else if (Pfn1->u3.e1.CacheAttribute == MiNonCached)
+    {
+        /* Write through, no caching */
+        MI_PAGE_DISABLE_CACHE(&TempPte);
+        MI_PAGE_WRITE_THROUGH(&TempPte);
+    }
+
+    /* Make the system PTE valid with our PFN */
+    MI_WRITE_VALID_PTE(ZeroPte, TempPte);
+
+    /* Get the address it maps to, and zero it out */
+    ZeroAddress = MiPteToAddress(ZeroPte);
+    KeZeroPages(ZeroAddress, PAGE_SIZE);
+
+    /* Now get rid of it */
+    MiReleaseSystemPtes(ZeroPte, 1, SystemPteSpace);
+}
+
 NTSTATUS
 NTAPI
 MiResolveDemandZeroFault(IN PVOID Address,
@@ -93,13 +138,24 @@ MiResolveDemandZeroFault(IN PVOID Address,
 {
     PFN_NUMBER PageFrameNumber;
     MMPTE TempPte;
+    BOOLEAN NeedZero = FALSE;
     DPRINT("ARM3 Demand Zero Page Fault Handler for address: %p in process: %p\n",
             Address,
             Process);
     
-    /* Must currently only be called by paging path, for system addresses only */
+    /* Must currently only be called by paging path */
     ASSERT(OldIrql == MM_NOIRQL);
-    ASSERT(Process == NULL);
+    if (Process)
+    {
+        /* Sanity check */
+        ASSERT(MI_IS_PAGE_TABLE_ADDRESS(PointerPte));
+
+        /* No forking yet */
+        ASSERT(Process->ForkInProgress == NULL);
+        
+        /* We'll need a zero page */
+        NeedZero = TRUE;
+    }
         
     //
     // Lock the PFN database
@@ -124,11 +180,31 @@ MiResolveDemandZeroFault(IN PVOID Address,
     //
     InterlockedIncrement(&KeGetCurrentPrcb()->MmDemandZeroCount);
     
-    /* Shouldn't see faults for user PTEs yet */
-    ASSERT(PointerPte > MiHighestUserPte);
+    /* Zero the page if need be */
+    if (NeedZero) MiZeroPfn(PageFrameNumber);
     
     /* Build the PTE */
-    MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, PointerPte->u.Soft.Protection, PageFrameNumber);
+    if (PointerPte <= MiHighestUserPte)
+    {
+        /* For user mode */
+        MI_MAKE_HARDWARE_PTE_USER(&TempPte,
+                                  PointerPte,
+                                  PointerPte->u.Soft.Protection,
+                                  PageFrameNumber);
+    }
+    else
+    {
+        /* For kernel mode */
+        MI_MAKE_HARDWARE_PTE(&TempPte,
+                             PointerPte,
+                             PointerPte->u.Soft.Protection,
+                             PageFrameNumber);
+    }
+    
+    /* Set it dirty if it's a writable page */
+    if (TempPte.u.Hard.Write) TempPte.u.Hard.Dirty = TRUE;
+    
+    /* Write it */
     MI_WRITE_VALID_PTE(PointerPte, TempPte);
 
     //
index 4410624..63b0942 100644 (file)
@@ -156,7 +156,7 @@ MmCreateKernelStack(IN BOOLEAN GuiStack,
     MI_MAKE_SOFTWARE_PTE(&InvalidPte, MM_NOACCESS);
 
     /* Setup the template stack PTE */
-    MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte + 1, MM_READWRITE, 0);
+    MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, PointerPte + 1, MM_READWRITE, 0);
     
     //
     // Acquire the PFN DB lock
@@ -270,7 +270,7 @@ MmGrowKernelStackEx(IN PVOID StackPointer,
         MiInitializePfn(PageFrameIndex, LimitPte, 1);
         
         /* Setup the template stack PTE */
-        MI_MAKE_HARDWARE_PTE(&TempPte, LimitPte, MM_READWRITE, PageFrameIndex);
+        MI_MAKE_HARDWARE_PTE_KERNEL(&TempPte, LimitPte, MM_READWRITE, PageFrameIndex);
         
         /* Write the valid PTE */
         MI_WRITE_VALID_PTE(LimitPte--, TempPte);