Author: ros-arm-bringup Date: Tue Jun 23 13:34:45 2009 New Revision: 41578
URL: http://svn.reactos.org/svn/reactos?rev=41578&view=rev Log: - Reimplement the way zeroing PTEs are used: - First, switch to using system PTEs as it should've been from the beginning. Our original implementation was broken and prone to race conditions, which Dmitry graciously fixed. - We can now remove the MiZeroPageInternal hack that was used as a way to avoid deadlock/contention in the zero paths. - Zeroing PTEs is done at DPC level in ReactOS, to avoid ReactOS-specific race issues. In Windows NT, this operation is always done at passive. - Zeroing PTEs are similar to hyperspace PTEs, but they can be mapped in chunks for optimization. - ReactOS does not currently make use of this functionality, so zeroing is pretty slow, especially on bootup if you have lots of memory (all RAM is zeroed). - The existing ReactOS "compatibility layer" for hyperspace was augmented to seamlessly use the new zeroing PTE API. - You must now unmap zeroing PTEs -- MiZeroPage was modified to do this. - System PTE binning, NBQUEUES and SLISTS would optimize this further. TBD. - Once again, tested on the trinity of supported emulators.
Modified: trunk/reactos/ntoskrnl/include/internal/mm.h trunk/reactos/ntoskrnl/mm/ARM3/hypermap.c trunk/reactos/ntoskrnl/mm/freelist.c trunk/reactos/ntoskrnl/mm/kmap.c
Modified: trunk/reactos/ntoskrnl/include/internal/mm.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/m... ============================================================================== --- trunk/reactos/ntoskrnl/include/internal/mm.h [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/include/internal/mm.h [iso-8859-1] Tue Jun 23 13:34:45 2009 @@ -1155,7 +1155,13 @@
PVOID NTAPI -MiMapPageToZeroInHyperSpace(IN PFN_NUMBER Page); +MiMapPagesToZeroInHyperSpace(IN PMMPFN *Pages, + IN PFN_NUMBER NumberOfPages); + +VOID +NTAPI +MiUnmapPagesInZeroSpace(IN PVOID VirtualAddress, + IN PFN_NUMBER NumberOfPages);
// // ReactOS Compatibility Layer @@ -1166,6 +1172,14 @@ { HyperProcess = (PEPROCESS)KeGetCurrentThread()->ApcState.Process; return MiMapPageInHyperSpace(HyperProcess, Page, &HyperIrql); +} + +PVOID +FORCEINLINE +MiMapPageToZeroInHyperSpace(IN PFN_NUMBER Page) +{ + PMMPFN Pfn1 = MiGetPfnEntry(Page); + return MiMapPagesToZeroInHyperSpace(&Pfn1, 1); }
#define MmDeleteHyperspaceMapping(x) MiUnmapPageInHyperSpace(HyperProcess, x, HyperIrql);
Modified: trunk/reactos/ntoskrnl/mm/ARM3/hypermap.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/hypermap.c... ============================================================================== --- trunk/reactos/ntoskrnl/mm/ARM3/hypermap.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/ARM3/hypermap.c [iso-8859-1] Tue Jun 23 13:34:45 2009 @@ -109,42 +109,101 @@
PVOID NTAPI -MiMapPageToZeroInHyperSpace(IN PFN_NUMBER Page) +MiMapPagesToZeroInHyperSpace(IN PMMPFN *Pages, + IN PFN_NUMBER NumberOfPages) { MMPTE TempPte; PMMPTE PointerPte; - PVOID Address; - - // - // Never accept page 0 - // - ASSERT(Page != 0); - - // - // Build the PTE - // + PFN_NUMBER Offset, PageFrameIndex; + PMMPFN Page; + + // + // Sanity checks + // + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + ASSERT(NumberOfPages != 0); + ASSERT(NumberOfPages <= (MI_ZERO_PTES - 1)); + + // + // Pick the first zeroing PTE + // + PointerPte = MiFirstReservedZeroingPte; + + // + // Now get the first free PTE + // + Offset = PFN_FROM_PTE(PointerPte); + if (NumberOfPages > Offset) + { + // + // Reset the PTEs + // + Offset = MI_ZERO_PTES - 1; + PointerPte->u.Hard.PageFrameNumber = Offset; + KeFlushProcessTb(); + } + + // + // Prepare the next PTE + // + PointerPte->u.Hard.PageFrameNumber = Offset - NumberOfPages; + + // + // Write the current PTE + // + PointerPte += (Offset + 1); TempPte = HyperTemplatePte; - TempPte.u.Hard.PageFrameNumber = Page; - - // - // Get the Zero PTE and its address - // - PointerPte = MiAddressToPte(MI_ZERO_PTE); - Address = (PVOID)((ULONG_PTR)PointerPte << 10); - - // - // Invalidate the old address - // - __invlpg(Address); - - // - // Write the current PTE - // - TempPte.u.Hard.PageFrameNumber = Page; - *PointerPte = TempPte; - + TempPte.u.Hard.Global = FALSE; // Hyperspace is local! + do + { + // + // Get the first page entry and its PFN + // + Page = *Pages++; + PageFrameIndex = MiGetPfnEntryIndex(Page); + + // + // Write the PFN + // + TempPte.u.Hard.PageFrameNumber = PageFrameIndex; + + // + // Set the correct PTE to write to, and set its new value + // + PointerPte--; + ASSERT(PointerPte->u.Hard.Valid == 0); + ASSERT(TempPte.u.Hard.Valid == 1); + *PointerPte = TempPte; + } while (--NumberOfPages); + // // Return the address // - return Address; -} + return MiPteToAddress(PointerPte); +} + +VOID +NTAPI +MiUnmapPagesInZeroSpace(IN PVOID VirtualAddress, + IN PFN_NUMBER NumberOfPages) +{ + PMMPTE PointerPte; + + // + // Sanity checks + // + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); + ASSERT (NumberOfPages != 0); + ASSERT (NumberOfPages <= (MI_ZERO_PTES - 1)); + + // + // Get the first PTE for the mapped zero VA + // + PointerPte = MiAddressToPte(VirtualAddress); + + // + // Blow away the mapped zero PTEs + // + RtlZeroMemory(PointerPte, NumberOfPages * sizeof(MMPTE)); +} +
Modified: trunk/reactos/ntoskrnl/mm/freelist.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/freelist.c?rev=... ============================================================================== --- trunk/reactos/ntoskrnl/mm/freelist.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/freelist.c [iso-8859-1] Tue Jun 23 13:34:45 2009 @@ -938,21 +938,6 @@ return NumberOfPagesFound; }
-static -NTSTATUS -MiZeroPageInternal(PFN_TYPE Page) -{ - PVOID TempAddress; - - TempAddress = MiMapPageToZeroInHyperSpace(Page); - if (TempAddress == NULL) - { - return(STATUS_NO_MEMORY); - } - memset(TempAddress, 0, PAGE_SIZE); - return(STATUS_SUCCESS); -} - NTSTATUS NTAPI MmZeroPageThreadMain(PVOID Ignored) @@ -1000,7 +985,7 @@ PageDescriptor->Flags.Type = MM_PHYSICAL_PAGE_USED; KeReleaseQueuedSpinLock(LockQueuePfnLock, oldIrql); Pfn = PageDescriptor - MmPfnDatabase; - Status = MiZeroPageInternal(Pfn); + Status = MiZeroPage(Pfn);
oldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock); if (PageDescriptor->MapCount != 0)
Modified: trunk/reactos/ntoskrnl/mm/kmap.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/kmap.c?rev=4157... ============================================================================== --- trunk/reactos/ntoskrnl/mm/kmap.c [iso-8859-1] (original) +++ trunk/reactos/ntoskrnl/mm/kmap.c [iso-8859-1] Tue Jun 23 13:34:45 2009 @@ -21,18 +21,18 @@ NTAPI MiZeroPage(PFN_TYPE Page) { - PEPROCESS Process; KIRQL Irql; PVOID TempAddress;
- Process = PsGetCurrentProcess(); - TempAddress = MiMapPageInHyperSpace(Process, Page, &Irql); + Irql = KeRaiseIrqlToDpcLevel(); + TempAddress = MiMapPageToZeroInHyperSpace(Page); if (TempAddress == NULL) { return(STATUS_NO_MEMORY); } memset(TempAddress, 0, PAGE_SIZE); - MiUnmapPageInHyperSpace(Process, TempAddress, Irql); + MiUnmapPagesInZeroSpace(TempAddress, 1); + KeLowerIrql(Irql); return(STATUS_SUCCESS); }