Author: sir_richard
Date: Wed May 12 23:37:19 2010
New Revision: 47186
URL: http://svn.reactos.org/svn/reactos?rev=47186&view=rev
Log:
[NTOS]: When grabbing physically contigous pages from the zero or free list, make sure to re-initialize their PFN entries correctly, since their data might be stale. Fixes potential weird memory corruption bugs.
[NTOS]: Physically contiguous memory allocations are not guaranteed to be zeroed, so do not zero the pages.
[NTOS]: When allocating contigous memory, mark the PFN entries appropriately after mapping the I/O ranges.
[NTOS]: When freeing contiguous memory, assert that all the freed pages correspond to PFN entries that we expect to have allocated for this purpose. Detects (not neccessarily fixes) memory corruption issues in contiguous memory allocations.
[NTOS]: These changes mostly affect certain network card and sound card systems/real hardware, they fix possible bugs and detect corruption that was otherwise going by unnoticed.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/contmem.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/contmem.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/contmem.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/contmem.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/contmem.c [iso-8859-1] Wed May 12 23:37:19 2010
@@ -132,23 +132,14 @@
//
MiUnlinkFreeOrZeroedPage(Pfn1);
Pfn1->u3.e2.ReferenceCount = 1;
+ Pfn1->u2.ShareCount = 1;
+ Pfn1->u3.e1.PageLocation = ActiveAndValid;
+ Pfn1->u3.e1.StartOfAllocation = 0;
+ Pfn1->u3.e1.EndOfAllocation = 0;
+ Pfn1->u3.e1.PrototypePte = 0;
+ Pfn1->u4.VerifierAllocation = 0;
+ Pfn1->PteAddress = (PVOID)0xBAADF00D;
- //
- // Check if it was already zeroed
- //
- if (Pfn1->u3.e1.PageLocation != ZeroedPageList)
- {
- //
- // It wasn't, so zero it
- //
- MiZeroPage(MiGetPfnEntryIndex(Pfn1));
- }
-
- //
- // Mark it in use
- //
- Pfn1->u3.e1.PageLocation = ActiveAndValid;
-
//
// Check if this is the last PFN, otherwise go on
//
@@ -331,7 +322,10 @@
{
PFN_NUMBER Page;
PHYSICAL_ADDRESS PhysicalAddress;
- PAGED_CODE ();
+ PMMPFN Pfn1, EndPfn;
+ PMMPTE PointerPte;
+ PVOID BaseAddress;
+ PAGED_CODE();
ASSERT(SizeInPages != 0);
//
@@ -348,7 +342,22 @@
// We'll just piggyback on the I/O memory mapper
//
PhysicalAddress.QuadPart = Page << PAGE_SHIFT;
- return MmMapIoSpace(PhysicalAddress, SizeInPages << PAGE_SHIFT, CacheType);
+ BaseAddress = MmMapIoSpace(PhysicalAddress, SizeInPages << PAGE_SHIFT, CacheType);
+ ASSERT(BaseAddress);
+
+ /* Loop the PFN entries */
+ Pfn1 = MiGetPfnEntry(Page);
+ EndPfn = Pfn1 + SizeInPages;
+ PointerPte = MiAddressToPte(BaseAddress);
+ do
+ {
+ /* Write the PTE address */
+ Pfn1->PteAddress = PointerPte++;
+ Pfn1->u4.PteFrame = PFN_FROM_PTE(MiAddressToPte(PointerPte));
+ } while (Pfn1++ < EndPfn);
+
+ /* Return the address */
+ return BaseAddress;
}
PVOID
@@ -437,6 +446,7 @@
KIRQL OldIrql;
PFN_NUMBER PageFrameIndex, LastPage, PageCount;
PMMPFN Pfn1, StartPfn;
+ PMMPTE PointerPte;
PAGED_CODE();
//
@@ -455,10 +465,9 @@
return;
}
- //
- // Otherwise, get the PTE and page number for the allocation
- //
- PageFrameIndex = PFN_FROM_PTE(MiAddressToPte(BaseAddress));
+ /* Get the PTE and frame number for the allocation*/
+ PointerPte = MiAddressToPte(BaseAddress);
+ PageFrameIndex = PFN_FROM_PTE(PointerPte);
//
// Now get the PFN entry for this, and make sure it's the correct one
@@ -469,11 +478,11 @@
//
// This probably means you did a free on an address that was in between
//
- KeBugCheckEx (BAD_POOL_CALLER,
- 0x60,
- (ULONG_PTR)BaseAddress,
- 0,
- 0);
+ KeBugCheckEx(BAD_POOL_CALLER,
+ 0x60,
+ (ULONG_PTR)BaseAddress,
+ 0,
+ 0);
}
//
@@ -482,16 +491,21 @@
StartPfn = Pfn1;
Pfn1->u3.e1.StartOfAllocation = 0;
- //
- // Look the PFNs
- //
+ /* Look the PFNs until we find the one that marks the end of the allocation */
do
{
- //
- // Until we find the one that marks the end of the allocation
- //
+ /* Make sure these are the pages we setup in the allocation routine */
+ ASSERT(Pfn1->u3.e2.ReferenceCount == 1);
+ ASSERT(Pfn1->u2.ShareCount == 1);
+ ASSERT(Pfn1->PteAddress == PointerPte);
+ ASSERT(Pfn1->u3.e1.PageLocation == ActiveAndValid);
+ ASSERT(Pfn1->u4.VerifierAllocation == 0);
+ ASSERT(Pfn1->u3.e1.PrototypePte == 0);
+
+ /* Keep going for assertions */
+ PointerPte++;
} while (Pfn1++->u3.e1.EndOfAllocation == 0);
-
+
//
// Found it, unmark it
//
Author: sir_richard
Date: Wed May 12 22:57:21 2010
New Revision: 47184
URL: http://svn.reactos.org/svn/reactos?rev=47184&view=rev
Log:
[NTOS]: Move MiFindContiguousPages to ARM3/contmem.c since I don't know what it was doing in freelist.c. No code change.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/contmem.c
trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
trunk/reactos/ntoskrnl/mm/freelist.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/contmem.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/contmem.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/contmem.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/contmem.c [iso-8859-1] Wed May 12 22:57:21 2010
@@ -17,6 +17,194 @@
#include "../ARM3/miarm.h"
/* PRIVATE FUNCTIONS **********************************************************/
+
+PFN_NUMBER
+NTAPI
+MiFindContiguousPages(IN PFN_NUMBER LowestPfn,
+ IN PFN_NUMBER HighestPfn,
+ IN PFN_NUMBER BoundaryPfn,
+ IN PFN_NUMBER SizeInPages,
+ IN MEMORY_CACHING_TYPE CacheType)
+{
+ PFN_NUMBER Page, PageCount, LastPage, Length, BoundaryMask;
+ ULONG i = 0;
+ PMMPFN Pfn1, EndPfn;
+ KIRQL OldIrql;
+ PAGED_CODE ();
+ ASSERT(SizeInPages != 0);
+
+ //
+ // Convert the boundary PFN into an alignment mask
+ //
+ BoundaryMask = ~(BoundaryPfn - 1);
+
+ //
+ // Loop all the physical memory blocks
+ //
+ do
+ {
+ //
+ // Capture the base page and length of this memory block
+ //
+ Page = MmPhysicalMemoryBlock->Run[i].BasePage;
+ PageCount = MmPhysicalMemoryBlock->Run[i].PageCount;
+
+ //
+ // Check how far this memory block will go
+ //
+ LastPage = Page + PageCount;
+
+ //
+ // Trim it down to only the PFNs we're actually interested in
+ //
+ if ((LastPage - 1) > HighestPfn) LastPage = HighestPfn + 1;
+ if (Page < LowestPfn) Page = LowestPfn;
+
+ //
+ // Skip this run if it's empty or fails to contain all the pages we need
+ //
+ if (!(PageCount) || ((Page + SizeInPages) > LastPage)) continue;
+
+ //
+ // Now scan all the relevant PFNs in this run
+ //
+ Length = 0;
+ for (Pfn1 = MiGetPfnEntry(Page); Page < LastPage; Page++, Pfn1++)
+ {
+ //
+ // If this PFN is in use, ignore it
+ //
+ if (MiIsPfnInUse(Pfn1)) continue;
+
+ //
+ // If we haven't chosen a start PFN yet and the caller specified an
+ // alignment, make sure the page matches the alignment restriction
+ //
+ if ((!(Length) && (BoundaryPfn)) &&
+ (((Page ^ (Page + SizeInPages - 1)) & BoundaryMask)))
+ {
+ //
+ // It does not, so bail out
+ //
+ continue;
+ }
+
+ //
+ // Increase the number of valid pages, and check if we have enough
+ //
+ if (++Length == SizeInPages)
+ {
+ //
+ // It appears we've amassed enough legitimate pages, rollback
+ //
+ Pfn1 -= (Length - 1);
+ Page -= (Length - 1);
+
+ //
+ // Acquire the PFN lock
+ //
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ do
+ {
+ //
+ // Things might've changed for us. Is the page still free?
+ //
+ if (MiIsPfnInUse(Pfn1)) break;
+
+ //
+ // So far so good. Is this the last confirmed valid page?
+ //
+ if (!--Length)
+ {
+ //
+ // Sanity check that we didn't go out of bounds
+ //
+ ASSERT(i != MmPhysicalMemoryBlock->NumberOfRuns);
+
+ //
+ // Loop until all PFN entries have been processed
+ //
+ EndPfn = Pfn1 - SizeInPages + 1;
+ do
+ {
+ //
+ // This PFN is now a used page, set it up
+ //
+ MiUnlinkFreeOrZeroedPage(Pfn1);
+ Pfn1->u3.e2.ReferenceCount = 1;
+
+ //
+ // Check if it was already zeroed
+ //
+ if (Pfn1->u3.e1.PageLocation != ZeroedPageList)
+ {
+ //
+ // It wasn't, so zero it
+ //
+ MiZeroPage(MiGetPfnEntryIndex(Pfn1));
+ }
+
+ //
+ // Mark it in use
+ //
+ Pfn1->u3.e1.PageLocation = ActiveAndValid;
+
+ //
+ // Check if this is the last PFN, otherwise go on
+ //
+ if (Pfn1 == EndPfn) break;
+ Pfn1--;
+ } while (TRUE);
+
+ //
+ // Mark the first and last PFN so we can find them later
+ //
+ Pfn1->u3.e1.StartOfAllocation = 1;
+ (Pfn1 + SizeInPages - 1)->u3.e1.EndOfAllocation = 1;
+
+ //
+ // Now it's safe to let go of the PFN lock
+ //
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ //
+ // Quick sanity check that the last PFN is consistent
+ //
+ EndPfn = Pfn1 + SizeInPages;
+ ASSERT(EndPfn == MiGetPfnEntry(Page + 1));
+
+ //
+ // Compute the first page, and make sure it's consistent
+ //
+ Page -= SizeInPages - 1;
+ ASSERT(Pfn1 == MiGetPfnEntry(Page));
+ ASSERT(Page != 0);
+ return Page;
+ }
+
+ //
+ // Keep going. The purpose of this loop is to reconfirm that
+ // after acquiring the PFN lock these pages are still usable
+ //
+ Pfn1++;
+ Page++;
+ } while (TRUE);
+
+ //
+ // If we got here, something changed while we hadn't acquired
+ // the PFN lock yet, so we'll have to restart
+ //
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ Length = 0;
+ }
+ }
+ } while (++i != MmPhysicalMemoryBlock->NumberOfRuns);
+
+ //
+ // And if we get here, it means no suitable physical memory runs were found
+ //
+ return 0;
+}
PVOID
NTAPI
Modified: trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/miarm.h?r…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/miarm.h [iso-8859-1] Wed May 12 22:57:21 2010
@@ -621,4 +621,10 @@
VOID
);
+BOOLEAN
+NTAPI
+MiIsPfnInUse(
+ IN PMMPFN Pfn1
+);
+
/* EOF */
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] Wed May 12 22:57:21 2010
@@ -145,194 +145,6 @@
{
/* Standby list or higher, unlinked, and with references */
return !MiIsPfnFree(Pfn1);
-}
-
-PFN_NUMBER
-NTAPI
-MiFindContiguousPages(IN PFN_NUMBER LowestPfn,
- IN PFN_NUMBER HighestPfn,
- IN PFN_NUMBER BoundaryPfn,
- IN PFN_NUMBER SizeInPages,
- IN MEMORY_CACHING_TYPE CacheType)
-{
- PFN_NUMBER Page, PageCount, LastPage, Length, BoundaryMask;
- ULONG i = 0;
- PMMPFN Pfn1, EndPfn;
- KIRQL OldIrql;
- PAGED_CODE ();
- ASSERT(SizeInPages != 0);
-
- //
- // Convert the boundary PFN into an alignment mask
- //
- BoundaryMask = ~(BoundaryPfn - 1);
-
- //
- // Loop all the physical memory blocks
- //
- do
- {
- //
- // Capture the base page and length of this memory block
- //
- Page = MmPhysicalMemoryBlock->Run[i].BasePage;
- PageCount = MmPhysicalMemoryBlock->Run[i].PageCount;
-
- //
- // Check how far this memory block will go
- //
- LastPage = Page + PageCount;
-
- //
- // Trim it down to only the PFNs we're actually interested in
- //
- if ((LastPage - 1) > HighestPfn) LastPage = HighestPfn + 1;
- if (Page < LowestPfn) Page = LowestPfn;
-
- //
- // Skip this run if it's empty or fails to contain all the pages we need
- //
- if (!(PageCount) || ((Page + SizeInPages) > LastPage)) continue;
-
- //
- // Now scan all the relevant PFNs in this run
- //
- Length = 0;
- for (Pfn1 = MiGetPfnEntry(Page); Page < LastPage; Page++, Pfn1++)
- {
- //
- // If this PFN is in use, ignore it
- //
- if (MiIsPfnInUse(Pfn1)) continue;
-
- //
- // If we haven't chosen a start PFN yet and the caller specified an
- // alignment, make sure the page matches the alignment restriction
- //
- if ((!(Length) && (BoundaryPfn)) &&
- (((Page ^ (Page + SizeInPages - 1)) & BoundaryMask)))
- {
- //
- // It does not, so bail out
- //
- continue;
- }
-
- //
- // Increase the number of valid pages, and check if we have enough
- //
- if (++Length == SizeInPages)
- {
- //
- // It appears we've amassed enough legitimate pages, rollback
- //
- Pfn1 -= (Length - 1);
- Page -= (Length - 1);
-
- //
- // Acquire the PFN lock
- //
- OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
- do
- {
- //
- // Things might've changed for us. Is the page still free?
- //
- if (MiIsPfnInUse(Pfn1)) break;
-
- //
- // So far so good. Is this the last confirmed valid page?
- //
- if (!--Length)
- {
- //
- // Sanity check that we didn't go out of bounds
- //
- ASSERT(i != MmPhysicalMemoryBlock->NumberOfRuns);
-
- //
- // Loop until all PFN entries have been processed
- //
- EndPfn = Pfn1 - SizeInPages + 1;
- do
- {
- //
- // This PFN is now a used page, set it up
- //
- MiUnlinkFreeOrZeroedPage(Pfn1);
- Pfn1->u3.e2.ReferenceCount = 1;
-
- //
- // Check if it was already zeroed
- //
- if (Pfn1->u3.e1.PageLocation != ZeroedPageList)
- {
- //
- // It wasn't, so zero it
- //
- MiZeroPage(MiGetPfnEntryIndex(Pfn1));
- }
-
- //
- // Mark it in use
- //
- Pfn1->u3.e1.PageLocation = ActiveAndValid;
-
- //
- // Check if this is the last PFN, otherwise go on
- //
- if (Pfn1 == EndPfn) break;
- Pfn1--;
- } while (TRUE);
-
- //
- // Mark the first and last PFN so we can find them later
- //
- Pfn1->u3.e1.StartOfAllocation = 1;
- (Pfn1 + SizeInPages - 1)->u3.e1.EndOfAllocation = 1;
-
- //
- // Now it's safe to let go of the PFN lock
- //
- KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-
- //
- // Quick sanity check that the last PFN is consistent
- //
- EndPfn = Pfn1 + SizeInPages;
- ASSERT(EndPfn == MiGetPfnEntry(Page + 1));
-
- //
- // Compute the first page, and make sure it's consistent
- //
- Page -= SizeInPages - 1;
- ASSERT(Pfn1 == MiGetPfnEntry(Page));
- ASSERT(Page != 0);
- return Page;
- }
-
- //
- // Keep going. The purpose of this loop is to reconfirm that
- // after acquiring the PFN lock these pages are still usable
- //
- Pfn1++;
- Page++;
- } while (TRUE);
-
- //
- // If we got here, something changed while we hadn't acquired
- // the PFN lock yet, so we'll have to restart
- //
- KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
- Length = 0;
- }
- }
- } while (++i != MmPhysicalMemoryBlock->NumberOfRuns);
-
- //
- // And if we get here, it means no suitable physical memory runs were found
- //
- return 0;
}
PMDL