From d403f0ffd466d24a6c7505e3d54964d47c0ea6d7 Mon Sep 17 00:00:00 2001 From: Sir Richard Date: Thu, 22 Jul 2010 02:20:27 +0000 Subject: [PATCH] [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). svn path=/trunk/; revision=48175 --- reactos/ntoskrnl/mm/ARM3/miarm.h | 82 ++++++++++++++++++++++++-- reactos/ntoskrnl/mm/ARM3/pagfault.c | 90 ++++++++++++++++++++++++++--- reactos/ntoskrnl/mm/ARM3/procsup.c | 4 +- 3 files changed, 163 insertions(+), 13 deletions(-) diff --git a/reactos/ntoskrnl/mm/ARM3/miarm.h b/reactos/ntoskrnl/mm/ARM3/miarm.h index fb6de0ee725..e3e889951e2 100644 --- a/reactos/ntoskrnl/mm/ARM3/miarm.h +++ b/reactos/ntoskrnl/mm/ARM3/miarm.h @@ -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,15 +475,45 @@ 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(IN PMMPTE NewPte, - IN PMMPTE MappingPte, - IN ULONG ProtectionMask, - IN PFN_NUMBER PageFrameNumber) +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); @@ -492,6 +528,44 @@ MI_MAKE_HARDWARE_PTE(IN PMMPTE NewPte, 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); + + /* Start fresh */ + *NewPte = ValidKernelPte; + + /* Set the protection and page */ + NewPte->u.Hard.Owner = TRUE; + NewPte->u.Hard.PageFrameNumber = PageFrameNumber; + NewPte->u.Long |= MmProtectToPteMask[ProtectionMask]; +} + // // Returns if the page is physically resident (ie: a large page) // FIXFIX: CISC/x86 only? diff --git a/reactos/ntoskrnl/mm/ARM3/pagfault.c b/reactos/ntoskrnl/mm/ARM3/pagfault.c index ad856419f36..eeb82a7712f 100644 --- a/reactos/ntoskrnl/mm/ARM3/pagfault.c +++ b/reactos/ntoskrnl/mm/ARM3/pagfault.c @@ -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); // diff --git a/reactos/ntoskrnl/mm/ARM3/procsup.c b/reactos/ntoskrnl/mm/ARM3/procsup.c index 4410624c387..63b0942f2e7 100644 --- a/reactos/ntoskrnl/mm/ARM3/procsup.c +++ b/reactos/ntoskrnl/mm/ARM3/procsup.c @@ -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);