Author: ion
Date: Tue Jul 31 07:11:52 2012
New Revision: 57000
URL: http://svn.reactos.org/svn/reactos?rev=57000&view=rev
Log:
[NTOSKRNL]: Additional support for session space. A few more ASSERTs and paranoia.
[NTOSKRNL]: Don't assume all prototype PTEs are cached, in fact none are in ReactOS at the moment! This resulted in the wrong hardware caching bits for the PEB/TEB and NLS Data which are using ARM3 section code.
[NTOSKRNL]: Also implement dirty page bit for prototype PTEs.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/pagfault.…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] Tue Jul 31 07:11:52 2012
@@ -23,7 +23,7 @@
#endif
LONG MmSystemLockPagesCount;
-
+
/* PRIVATE FUNCTIONS **********************************************************/
PMMPTE
@@ -305,8 +305,18 @@
/* Check if we need a zero page */
NeedZero = (OldIrql != MM_NOIRQL);
- /* Get the next system page color */
- Color = MI_GET_NEXT_COLOR();
+#if 0
+ /* Session-backed image views must be zeroed */
+ if ((Process == HYDRA_PROCESS) &&
+ ((MI_IS_SESSION_IMAGE_ADDRESS(Address)) ||
+ ((Address >= (PVOID)MiSessionViewStart) &&
+ (Address < (PVOID)MiSessionSpaceWs))))
+ {
+ NeedZero = TRUE;
+ }
+#endif
+ /* Hardcode unknown color */
+ Color = 0xFFFFFFFF;
}
/* Check if the PFN database should be acquired */
@@ -332,31 +342,31 @@
if (!Process) MI_SET_PROCESS2("Kernel Demand 0");
/* Do we need a zero page? */
- if ((NeedZero) && (Process))
+ if (Color != 0xFFFFFFFF)
{
/* Try to get one, if we couldn't grab a free page and zero it */
PageFrameNumber = MiRemoveZeroPageSafe(Color);
- if (PageFrameNumber)
- {
- /* We got a genuine zero page, stop worrying about it */
- NeedZero = FALSE;
- }
- else
+ if (!PageFrameNumber)
{
/* We'll need a free page and zero it manually */
PageFrameNumber = MiRemoveAnyPage(Color);
- }
- }
- else if (!NeedZero)
- {
- /* Process or system doesn't want a zero page, grab anything */
- PageFrameNumber = MiRemoveAnyPage(Color);
+ NeedZero = TRUE;
+ }
}
else
{
- /* System wants a zero page, obtain one */
- PageFrameNumber = MiRemoveZeroPage(Color);
- NeedZero = FALSE;
+ /* Get a color, and see if we should grab a zero or non-zero page */
+ Color = MI_GET_NEXT_COLOR();
+ if (!NeedZero)
+ {
+ /* Process or system doesn't want a zero page, grab anything */
+ PageFrameNumber = MiRemoveAnyPage(Color);
+ }
+ else
+ {
+ /* System wants a zero page, obtain one */
+ PageFrameNumber = MiRemoveZeroPage(Color);
+ }
}
/* Initialize it */
@@ -434,6 +444,7 @@
ULONG_PTR Protection;
PFN_NUMBER PageFrameIndex;
PMMPFN Pfn1, Pfn2;
+ BOOLEAN OriginalProtection, DirtyPage;
/* Must be called with an valid prototype PTE, with the PFN lock held */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
@@ -458,13 +469,40 @@
{
/* Get the protection from the PTE, there's no real Proto PTE data */
Protection = PointerPte->u.Soft.Protection;
+
+ /* Remember that we did not use the proto protection */
+ OriginalProtection = FALSE;
}
else
{
/* Get the protection from the original PTE link */
OriginalPte = &Pfn1->OriginalPte;
Protection = OriginalPte->u.Soft.Protection;
- }
+
+ /* Remember that we used the original protection */
+ OriginalProtection = TRUE;
+
+ /* Check if this was a write on a read only proto */
+ if ((StoreInstruction) && !(Protection & MM_READWRITE))
+ {
+ /* Clear the flag */
+ StoreInstruction = 0;
+ }
+ }
+
+ /* Check if this was a write on a non-COW page */
+ DirtyPage = FALSE;
+ if ((StoreInstruction) && ((Protection & MM_WRITECOPY) != MM_WRITECOPY))
+ {
+ /* Then the page should be marked dirty */
+ DirtyPage = TRUE;
+
+ /* ReactOS check */
+ ASSERT(Pfn1->OriginalPte.u.Soft.Prototype != 0);
+ }
+
+ /* Not yet handled by ReactOS */
+ ASSERT(LockedPfn == NULL);
/* Release the PFN lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
@@ -472,6 +510,20 @@
/* Remove caching bits */
Protection &= ~(MM_NOCACHE | MM_NOACCESS);
+ /* 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);
+ }
+
/* Check if this is a kernel or user address */
if (Address < MmSystemRangeStart)
{
@@ -484,10 +536,17 @@
MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, PageFrameIndex);
}
+ /* Set the dirty flag if needed */
+ if (DirtyPage) TempPte.u.Hard.Dirty = TRUE;
+
/* Write the PTE */
MI_WRITE_VALID_PTE(PointerPte, TempPte);
+ /* Reset the protection if needed */
+ if (OriginalProtection) Protection = MM_ZERO_ACCESS;
+
/* Return success */
+ ASSERT(PointerPte == MiAddressToPte(Address));
return STATUS_SUCCESS;
}
@@ -823,31 +882,31 @@
/* Has the PTE been made valid yet? */
if (!SuperProtoPte->u.Hard.Valid)
{
- UNIMPLEMENTED;
- while (TRUE);
- }
- else
- {
- /* Resolve the fault -- this will release the PFN lock */
- ASSERT(PointerPte->u.Hard.Valid == 0);
- Status = MiResolveProtoPteFault(StoreInstruction,
- Address,
- PointerPte,
- PointerProtoPte,
- NULL,
- NULL,
- NULL,
- Process,
- LockIrql,
- TrapInformation);
- ASSERT(Status == STATUS_SUCCESS);
-
- /* Complete this as a transition fault */
- ASSERT(OldIrql == KeGetCurrentIrql());
- ASSERT(OldIrql <= APC_LEVEL);
- ASSERT(KeAreAllApcsDisabled() == TRUE);
- return Status;
- }
+ ASSERT(FALSE);
+ }
+ else if (PointerPte->u.Hard.Valid == 1)
+ {
+ ASSERT(FALSE);
+ }
+
+ /* Resolve the fault -- this will release the PFN lock */
+ Status = MiResolveProtoPteFault(StoreInstruction,
+ Address,
+ PointerPte,
+ PointerProtoPte,
+ NULL,
+ NULL,
+ NULL,
+ Process,
+ LockIrql,
+ TrapInformation);
+ ASSERT(Status == STATUS_SUCCESS);
+
+ /* Complete this as a transition fault */
+ ASSERT(OldIrql == KeGetCurrentIrql());
+ ASSERT(OldIrql <= APC_LEVEL);
+ ASSERT(KeAreAllApcsDisabled() == TRUE);
+ return Status;
}
else
{
Author: ion
Date: Tue Jul 31 06:47:47 2012
New Revision: 56999
URL: http://svn.reactos.org/svn/reactos?rev=56999&view=rev
Log:
[NTOSKRNL]: Multiple fixes to faulting paths. Make some checks more explicit, support lock pages counter, update dirty bit when needed, and stub further support for session space.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/pagfault.…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/pagfault.c [iso-8859-1] Tue Jul 31 06:47:47 2012
@@ -17,10 +17,13 @@
/* GLOBALS ********************************************************************/
+#define HYDRA_PROCESS (PEPROCESS)1
#if MI_TRACE_PFNS
BOOLEAN UserPdeFault = FALSE;
#endif
+LONG MmSystemLockPagesCount;
+
/* PRIVATE FUNCTIONS **********************************************************/
PMMPTE
@@ -35,8 +38,70 @@
/* No prototype/section support for now */
*ProtoVad = NULL;
- /* Check if this is a page table address */
- if (MI_IS_PAGE_TABLE_ADDRESS(VirtualAddress))
+ /* User or kernel fault? */
+ if (VirtualAddress <= MM_HIGHEST_USER_ADDRESS)
+ {
+ /* Special case for shared data */
+ if (PAGE_ALIGN(VirtualAddress) == (PVOID)MM_SHARED_USER_DATA_VA)
+ {
+ /* It's a read-only page */
+ *ProtectCode = MM_READONLY;
+ return MmSharedUserDataPte;
+ }
+
+ /* Find the VAD, it might not exist if the address is bogus */
+ Vad = MiLocateAddress(VirtualAddress);
+ if (!Vad)
+ {
+ /* Bogus virtual address */
+ *ProtectCode = MM_NOACCESS;
+ return NULL;
+ }
+
+ /* ReactOS does not handle physical memory VADs yet */
+ ASSERT(Vad->u.VadFlags.VadType != VadDevicePhysicalMemory);
+
+ /* Check if it's a section, or just an allocation */
+ if (Vad->u.VadFlags.PrivateMemory)
+ {
+ /* ReactOS does not handle AWE VADs yet */
+ ASSERT(Vad->u.VadFlags.VadType != VadAwe);
+
+ /* This must be a TEB/PEB VAD */
+ if (Vad->u.VadFlags.MemCommit)
+ {
+ /* It's committed, so return the VAD protection */
+ *ProtectCode = (ULONG)Vad->u.VadFlags.Protection;
+ }
+ else
+ {
+ /* It has not yet been committed, so return no access */
+ *ProtectCode = MM_NOACCESS;
+ }
+
+ /* In both cases, return no PTE */
+ return NULL;
+ }
+ else
+ {
+ /* ReactOS does not supoprt these VADs yet */
+ ASSERT(Vad->u.VadFlags.VadType != VadImageMap);
+ ASSERT(Vad->u2.VadFlags2.ExtendableFile == 0);
+
+ /* Return the proto VAD */
+ *ProtoVad = Vad;
+
+ /* Get the prototype PTE for this page */
+ PointerPte = (((ULONG_PTR)VirtualAddress >> PAGE_SHIFT) - Vad->StartingVpn) + Vad->FirstPrototypePte;
+ ASSERT(PointerPte != NULL);
+ ASSERT(PointerPte <= Vad->LastContiguousPte);
+
+ /* Return the Prototype PTE and the protection for the page mapping */
+ *ProtectCode = (ULONG)Vad->u.VadFlags.Protection;
+ return PointerPte;
+ }
+ }
+ else if (MI_IS_PAGE_TABLE_ADDRESS(VirtualAddress))
{
/* This should never happen, as these addresses are handled by the double-maping */
if (((PMMPTE)VirtualAddress >= MiAddressToPte(MmPagedPoolStart)) &&
@@ -51,61 +116,15 @@
*ProtectCode = MM_READWRITE;
return NULL;
}
-
- /* Should not be a session address */
- ASSERT(MI_IS_SESSION_ADDRESS(VirtualAddress) == FALSE);
-
- /* Special case for shared data */
- if (PAGE_ALIGN(VirtualAddress) == (PVOID)MM_SHARED_USER_DATA_VA)
- {
- /* It's a read-only page */
- *ProtectCode = MM_READONLY;
- return MmSharedUserDataPte;
- }
-
- /* Find the VAD, it might not exist if the address is bogus */
- Vad = MiLocateAddress(VirtualAddress);
- if (!Vad)
- {
- /* Bogus virtual address */
- *ProtectCode = MM_NOACCESS;
- return NULL;
- }
-
- /* This must be a VM VAD */
- ASSERT(Vad->u.VadFlags.VadType == VadNone);
-
- /* Check if it's a section, or just an allocation */
- if (Vad->u.VadFlags.PrivateMemory)
- {
- /* This must be a TEB/PEB VAD */
- if (Vad->u.VadFlags.MemCommit)
- {
- /* It's committed, so return the VAD protection */
- *ProtectCode = (ULONG)Vad->u.VadFlags.Protection;
- }
- else
- {
- /* It has not yet been committed, so return no access */
- *ProtectCode = MM_NOACCESS;
- }
- return NULL;
- }
- else
- {
- /* Return the proto VAD */
- ASSERT(Vad->u2.VadFlags2.ExtendableFile == 0);
- *ProtoVad = Vad;
-
- /* Get the prototype PTE for this page */
- PointerPte = (((ULONG_PTR)VirtualAddress >> PAGE_SHIFT) - Vad->StartingVpn) + Vad->FirstPrototypePte;
- ASSERT(PointerPte <= Vad->LastContiguousPte);
- ASSERT(PointerPte != NULL);
-
- /* Return the Prototype PTE and the protection for the page mapping */
- *ProtectCode = (ULONG)Vad->u.VadFlags.Protection;
- return PointerPte;
- }
+ else if (MI_IS_SESSION_ADDRESS(VirtualAddress))
+ {
+ /* ReactOS does not have an image list yet, so bail out to failure case */
+ ASSERT(IsListEmpty(&MmSessionSpace->ImageList));
+ }
+
+ /* Default case -- failure */
+ *ProtectCode = MM_NOACCESS;
+ return NULL;
}
#if (_MI_PAGING_LEVELS == 2)
@@ -132,19 +151,23 @@
NTSTATUS
FASTCALL
+MiCheckPdeForSessionSpace(IN PVOID Address)
+{
+ /* Code not yet tested */
+ ASSERT(FALSE);
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+FASTCALL
MiCheckPdeForPagedPool(IN PVOID Address)
{
PMMPDE PointerPde;
NTSTATUS Status = STATUS_SUCCESS;
- if (MI_IS_SESSION_ADDRESS(Address))
- {
- DPRINT1("Unexpected session fault: %p %p %p\n", Address, MmSessionBase, MiSessionSpaceEnd);
- }
-
- /* No session support in ReactOS yet */
- ASSERT(MI_IS_SESSION_ADDRESS(Address) == FALSE);
- ASSERT(MI_IS_SESSION_PTE(Address) == FALSE);
+ /* Check session PDE */
+ if (MI_IS_SESSION_ADDRESS(Address)) return MiCheckPdeForSessionSpace(Address);
+ if (MI_IS_SESSION_PTE(Address)) return MiCheckPdeForSessionSpace(Address);
//
// Check if this is a fault while trying to access the page table itself
@@ -178,15 +201,11 @@
//
if (PointerPde->u.Hard.Valid == 0)
{
-#ifdef _M_AMD64
- ASSERT(FALSE);
-#else
//
// Copy it from our double-mapped system page directory
//
InterlockedExchangePte(PointerPde,
MmSystemPagePtes[((ULONG_PTR)PointerPde & (SYSTEM_PD_SIZE - 1)) / sizeof(MMPTE)].u.Long);
-#endif
}
//
@@ -260,12 +279,13 @@
MMPTE TempPte;
BOOLEAN NeedZero = FALSE, HaveLock = FALSE;
ULONG Color;
+ PMMPFN Pfn1;
DPRINT("ARM3 Demand Zero Page Fault Handler for address: %p in process: %p\n",
Address,
Process);
/* Must currently only be called by paging path */
- if ((Process) && (OldIrql == MM_NOIRQL))
+ if ((Process > HYDRA_PROCESS) && (OldIrql == MM_NOIRQL))
{
/* Sanity check */
ASSERT(MI_IS_PAGE_TABLE_ADDRESS(PointerPte));
@@ -299,15 +319,19 @@
/* We either manually locked the PFN DB, or already came with it locked */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
-
- /* Do we need a zero page? */
ASSERT(PointerPte->u.Hard.Valid == 0);
+
+ /* Assert we have enough pages */
+ ASSERT(MmAvailablePages >= 32);
+
#if MI_TRACE_PFNS
if (UserPdeFault) MI_SET_USAGE(MI_USAGE_PAGE_TABLE);
if (!UserPdeFault) MI_SET_USAGE(MI_USAGE_DEMAND_ZERO);
#endif
if (Process) MI_SET_PROCESS2(Process->ImageFileName);
if (!Process) MI_SET_PROCESS2("Kernel Demand 0");
+
+ /* Do we need a zero page? */
if ((NeedZero) && (Process))
{
/* Try to get one, if we couldn't grab a free page and zero it */
@@ -338,11 +362,18 @@
/* Initialize it */
MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
+ /* Do we have the lock? */
+ if (HaveLock)
+ {
+ /* Release it */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* Update performance counters */
+ if (Process > HYDRA_PROCESS) Process->NumberOfPrivatePages++;
+ }
+
/* Increment demand zero faults */
- KeGetCurrentPrcb()->MmDemandZeroCount++;
-
- /* Release PFN lock if needed */
- if (HaveLock) KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ InterlockedIncrement(&KeGetCurrentPrcb()->MmDemandZeroCount);
/* Zero the page if need be */
if (NeedZero) MiZeroPfn(PageFrameNumber);
@@ -370,6 +401,17 @@
/* Write it */
MI_WRITE_VALID_PTE(PointerPte, TempPte);
+
+ /* Did we manually acquire the lock */
+ if (HaveLock)
+ {
+ /* Get the PFN entry */
+ Pfn1 = MI_PFN_ELEMENT(PageFrameNumber);
+
+ /* Windows does these sanity checks */
+ ASSERT(Pfn1->u1.Event == 0);
+ ASSERT(Pfn1->u3.e1.PrototypePte == 0);
+ }
//
// It's all good now
@@ -385,13 +427,13 @@
IN PMMPTE PointerPte,
IN PMMPTE PointerProtoPte,
IN KIRQL OldIrql,
- IN PMMPFN Pfn1)
+ IN PMMPFN* LockedPfn)
{
MMPTE TempPte;
PMMPTE OriginalPte, PageTablePte;
ULONG_PTR Protection;
PFN_NUMBER PageFrameIndex;
- PMMPFN Pfn2;
+ PMMPFN Pfn1, Pfn2;
/* Must be called with an valid prototype PTE, with the PFN lock held */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
@@ -494,6 +536,9 @@
ASSERT(MmAvailablePages >= 0);
ASSERT(Pfn1->u4.InPageError == 0);
+ /* ReactOS checks for this */
+ ASSERT(MmAvailablePages > 32);
+
/* Was this a transition page in the valid list, or free/zero list? */
if (Pfn1->u3.e1.PageLocation == ActiveAndValid)
{
@@ -523,7 +568,8 @@
ASSERT(FALSE);
}
- /* FIXME: Update counter */
+ /* Update counter */
+ InterlockedIncrementSizeT(&MmSystemLockPagesCount);
/* We must be the first reference */
NewRefCount = InterlockedIncrement16((PSHORT)&Pfn1->u3.e2.ReferenceCount);
@@ -555,7 +601,8 @@
ASSERT(FALSE);
}
- /* FIXME: Update counter */
+ /* Update counter */
+ InterlockedDecrementSizeT(&MmSystemLockPagesCount);
}
}
@@ -585,7 +632,18 @@
(MmProtectToPteMask[PointerPte->u.Trans.Protection]) |
MiDetermineUserGlobalPteMask(PointerPte);
- /* FIXME: Set dirty bit */
+ /* Is the PTE writeable? */
+ if (((Pfn1->u3.e1.Modified) && (TempPte.u.Hard.Write)) &&
+ (TempPte.u.Hard.CopyOnWrite == 0))
+ {
+ /* Make it dirty */
+ TempPte.u.Hard.Dirty = TRUE;
+ }
+ else
+ {
+ /* Make it clean */
+ TempPte.u.Hard.Dirty = FALSE;
+ }
/* Write the valid PTE */
MI_WRITE_VALID_PTE(PointerPte, TempPte);
@@ -654,12 +712,24 @@
{
if (!PteContents.u.Proto.ReadOnly)
{
- /* FIXME: CHECK FOR ACCESS AND COW */
+ /* FIXME: CHECK FOR ACCESS */
+
+ /* Check for copy on write page */
+ if ((TempPte.u.Soft.Protection & MM_WRITECOPY) == MM_WRITECOPY)
+ {
+ /* Not yet supported */
+ ASSERT(FALSE);
+ }
}
}
else
{
- /* FIXME: Should check for COW */
+ /* Check for copy on write page */
+ if ((PteContents.u.Soft.Protection & MM_WRITECOPY) == MM_WRITECOPY)
+ {
+ /* Not yet supported */
+ ASSERT(FALSE);
+ }
}
/* Check for clone PTEs */
@@ -815,7 +885,8 @@
//
// The PTE must be invalid but not completely empty. It must also not be a
- // prototype PTE as that scenario should've been handled above
+ // prototype PTE as that scenario should've been handled above. These are
+ // all Windows checks
//
ASSERT(TempPte.u.Hard.Valid == 0);
ASSERT(TempPte.u.Soft.Prototype == 0);
@@ -823,7 +894,7 @@
//
// No transition or page file software PTEs in ARM3 yet, so this must be a
- // demand zero page
+ // demand zero page. These are all ReactOS checks
//
ASSERT(TempPte.u.Soft.Transition == 0);
ASSERT(TempPte.u.Soft.PageFileHigh == 0);