[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
This commit is contained in:
Sir Richard 2010-07-22 02:20:27 +00:00
parent 7c3bc09fa1
commit d403f0ffd4
3 changed files with 163 additions and 13 deletions

View 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,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?

View 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);
//

View 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);