Author: sir_richard Date: Thu Jul 22 02:20:27 2010 New Revision: 48175
URL: http://svn.reactos.org/svn/reactos?rev=48175&view=rev Log: [NTOS]: Learn to build User PTEs as well, with MI_MAKE_HARDWARE_PTE_USER. [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).
Modified: trunk/reactos/ntoskrnl/mm/ARM3/miarm.h trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c trunk/reactos/ntoskrnl/mm/ARM3/procsup.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/miarm.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/miarm.h?re... ============================================================================== --- trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] Thu Jul 22 02:20:27 2010 @@ -192,6 +192,12 @@
#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 @@ -470,7 +476,60 @@ #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 @@ -479,15 +538,30 @@ 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]; }
Modified: trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c... ============================================================================== --- trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] Thu Jul 22 02:20:27 2010 @@ -34,8 +34,7 @@ // // 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 @@ -82,6 +81,52 @@ // Return status // 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 @@ -93,13 +138,24 @@ { 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 @@ // 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);
//
Modified: trunk/reactos/ntoskrnl/mm/ARM3/procsup.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/procsup.c?... ============================================================================== --- trunk/reactos/ntoskrnl/mm/ARM3/procsup.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/ARM3/procsup.c [iso-8859-1] Thu Jul 22 02:20:27 2010 @@ -156,7 +156,7 @@ 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 @@ 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);