From a2cb9d5ee2d4bf18652f48875d75049f6bac141c Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Tue, 31 Jul 2012 07:11:52 +0000 Subject: [PATCH] [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. svn path=/trunk/; revision=57000 --- reactos/ntoskrnl/mm/ARM3/pagfault.c | 139 ++++++++++++++++++++-------- 1 file changed, 99 insertions(+), 40 deletions(-) diff --git a/reactos/ntoskrnl/mm/ARM3/pagfault.c b/reactos/ntoskrnl/mm/ARM3/pagfault.c index 856a44720f7..665cceba20c 100644 --- a/reactos/ntoskrnl/mm/ARM3/pagfault.c +++ b/reactos/ntoskrnl/mm/ARM3/pagfault.c @@ -23,7 +23,7 @@ BOOLEAN UserPdeFault = FALSE; #endif LONG MmSystemLockPagesCount; - + /* PRIVATE FUNCTIONS **********************************************************/ PMMPTE @@ -305,8 +305,18 @@ MiResolveDemandZeroFault(IN PVOID Address, /* 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 @@ MiResolveDemandZeroFault(IN PVOID Address, 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); + NeedZero = TRUE; } } - else 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); - 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 @@ MiCompleteProtoPteFault(IN BOOLEAN StoreInstruction, 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,20 +469,61 @@ MiCompleteProtoPteFault(IN BOOLEAN StoreInstruction, { /* 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); /* 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 @@ MiCompleteProtoPteFault(IN BOOLEAN StoreInstruction, 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 @@ MiDispatchFault(IN BOOLEAN StoreInstruction, /* Has the PTE been made valid yet? */ if (!SuperProtoPte->u.Hard.Valid) { - UNIMPLEMENTED; - while (TRUE); + ASSERT(FALSE); } - else + else if (PointerPte->u.Hard.Valid == 1) { - /* 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); } + + /* 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 {