Author: sir_richard
Date: Mon Oct 4 19:31:16 2010
New Revision: 48980
URL: http://svn.reactos.org/svn/reactos?rev=48980&view=rev
Log:
[NTOS]: Implement MmCreateArm3Section, which creates ARM3-backed sections, but only for pagefile-backed memory at the moment. It uses MiCreatePagingFileMap and creates the expected Segment, Subsection, ControlArea and Section objects described in Windows kernel internals literrature. It's surprisingly easy and only takes 200 lines of code.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/section.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/section.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/section.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/section.c [iso-8859-1] Mon Oct 4 19:31:16 2010
@@ -205,6 +205,210 @@
/* Success */
return TRUE;
+}
+
+NTSTATUS
+NTAPI
+MiCreatePagingFileMap(OUT PSEGMENT *Segment,
+ IN PSIZE_T MaximumSize,
+ IN ULONG ProtectionMask,
+ IN ULONG AllocationAttributes)
+{
+ SIZE_T SizeLimit;
+ PFN_NUMBER PteCount;
+ PMMPTE PointerPte;
+ MMPTE TempPte;
+ PCONTROL_AREA ControlArea;
+ PSEGMENT NewSegment;
+ PSUBSECTION Subsection;
+ PAGED_CODE();
+
+ /* No large pages in ARM3 yet */
+ ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0);
+
+ /* Pagefile-backed sections need a known size */
+ if (!(*MaximumSize)) return STATUS_INVALID_PARAMETER_4;
+
+ /* Calculate the maximum size possible, given the Prototype PTEs we'll need */
+ SizeLimit = MAXULONG_PTR - sizeof(SEGMENT);
+ SizeLimit /= sizeof(MMPTE);
+ SizeLimit <<= PAGE_SHIFT;
+
+ /* Fail if this size is too big */
+ if (*MaximumSize > SizeLimit) return STATUS_SECTION_TOO_BIG;
+
+ /* Calculate how many Prototype PTEs will be needed */
+ PteCount = (*MaximumSize + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ /* For commited memory, we must have a valid protection mask */
+ if (AllocationAttributes & SEC_COMMIT) ASSERT(ProtectionMask != 0);
+
+ /* The segment contains all the Prototype PTEs, allocate it in paged pool */
+ NewSegment = ExAllocatePoolWithTag(PagedPool,
+ sizeof(SEGMENT) +
+ sizeof(MMPTE) * (PteCount - 1),
+ 'tSmM');
+ ASSERT(NewSegment);
+ *Segment = NewSegment;
+
+ /* Now allocate the control area, which has the subsection structure */
+ ControlArea = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(CONTROL_AREA) + sizeof(SUBSECTION),
+ 'tCmM');
+ ASSERT(ControlArea);
+
+ /* And zero it out, filling the basic segmnet pointer and reference fields */
+ RtlZeroMemory(ControlArea, sizeof(CONTROL_AREA) + sizeof(SUBSECTION));
+ ControlArea->Segment = NewSegment;
+ ControlArea->NumberOfSectionReferences = 1;
+ ControlArea->NumberOfUserReferences = 1;
+
+ /* Convert allocation attributes to control area flags */
+ if (AllocationAttributes & SEC_BASED) ControlArea->u.Flags.Based = 1;
+ if (AllocationAttributes & SEC_RESERVE) ControlArea->u.Flags.Reserve = 1;
+ if (AllocationAttributes & SEC_COMMIT) ControlArea->u.Flags.Commit = 1;
+
+ /* The subsection follows, write the mask, PTE count and point back to the CA */
+ Subsection = (PSUBSECTION)(ControlArea + 1);
+ Subsection->ControlArea = ControlArea;
+ Subsection->PtesInSubsection = PteCount;
+ Subsection->u.SubsectionFlags.Protection = ProtectionMask;
+
+ /* Zero out the segment's prototype PTEs, and link it with the control area */
+ PointerPte = &NewSegment->ThePtes[0];
+ RtlZeroMemory(NewSegment, sizeof(SEGMENT));
+ NewSegment->PrototypePte = PointerPte;
+ NewSegment->ControlArea = ControlArea;
+
+ /* Save some extra accounting data for the segment as well */
+ NewSegment->u1.CreatingProcess = PsGetCurrentProcess();
+ NewSegment->SizeOfSegment = PteCount * PAGE_SIZE;
+ NewSegment->TotalNumberOfPtes = PteCount;
+ NewSegment->NonExtendedPtes = PteCount;
+
+ /* The subsection's base address is the first Prototype PTE in the segment */
+ Subsection->SubsectionBase = PointerPte;
+
+ /* Start with an empty PTE, unless this is a commit operation */
+ TempPte.u.Long = 0;
+ if (AllocationAttributes & SEC_COMMIT)
+ {
+ /* In which case, write down the protection mask in the Prototype PTEs */
+ TempPte.u.Soft.Protection = ProtectionMask;
+
+ /* For accounting, also mark these pages as being committed */
+ NewSegment->NumberOfCommittedPages = PteCount;
+ }
+
+ /* The template PTE itself for the segment should also have the mask set */
+ NewSegment->SegmentPteTemplate.u.Soft.Protection = ProtectionMask;
+
+ /* Write out the prototype PTEs, for now they're simply demand zero */
+ RtlFillMemoryUlong(PointerPte, PteCount * sizeof(MMPTE), TempPte.u.Long);
+ return STATUS_SUCCESS;
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+MmCreateArm3Section(OUT PVOID *SectionObject,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
+ IN PLARGE_INTEGER InputMaximumSize,
+ IN ULONG SectionPageProtection,
+ IN ULONG AllocationAttributes,
+ IN HANDLE FileHandle OPTIONAL,
+ IN PFILE_OBJECT FileObject OPTIONAL)
+{
+ SECTION Section;
+ PSECTION NewSection;
+ PSUBSECTION Subsection;
+ PSEGMENT NewSegment;
+ NTSTATUS Status;
+ PCONTROL_AREA ControlArea;
+ ULONG ProtectionMask;
+
+ /* ARM3 does not yet support this */
+ ASSERT(FileHandle == NULL);
+ ASSERT(FileObject == NULL);
+ ASSERT((AllocationAttributes & SEC_LARGE_PAGES) == 0);
+
+ /* Make the same sanity checks that the Nt interface should've validated */
+ ASSERT((AllocationAttributes & ~(SEC_COMMIT | SEC_RESERVE | SEC_BASED |
+ SEC_LARGE_PAGES | SEC_IMAGE | SEC_NOCACHE |
+ SEC_NO_CHANGE)) == 0);
+ ASSERT((AllocationAttributes & (SEC_COMMIT | SEC_RESERVE | SEC_IMAGE)) != 0);
+ ASSERT(!((AllocationAttributes & SEC_IMAGE) &&
+ (AllocationAttributes & (SEC_COMMIT | SEC_RESERVE |
+ SEC_NOCACHE | SEC_NO_CHANGE))));
+ ASSERT(!((AllocationAttributes & SEC_COMMIT) && (AllocationAttributes & SEC_RESERVE)));
+ ASSERT(!((SectionPageProtection & PAGE_NOCACHE) ||
+ (SectionPageProtection & PAGE_WRITECOMBINE) ||
+ (SectionPageProtection & PAGE_GUARD) ||
+ (SectionPageProtection & PAGE_NOACCESS)));
+
+ /* Convert section flag to page flag */
+ if (AllocationAttributes & SEC_NOCACHE) SectionPageProtection |= PAGE_NOCACHE;
+
+ /* Check to make sure the protection is correct. Nt* does this already */
+ ProtectionMask = MiMakeProtectionMask(SectionPageProtection);
+ if (ProtectionMask == MM_INVALID_PROTECTION) return STATUS_INVALID_PAGE_PROTECTION;
+
+ /* A handle must be supplied with SEC_IMAGE, and this is the no-handle path */
+ if (AllocationAttributes & SEC_IMAGE) return STATUS_INVALID_FILE_FOR_SECTION;
+
+ /* So this must be a pagefile-backed section, create the mappings needed */
+ Status = MiCreatePagingFileMap(&NewSegment,
+ (PSIZE_T)InputMaximumSize,
+ ProtectionMask,
+ AllocationAttributes);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Set the initial section object data */
+ Section.InitialPageProtection = SectionPageProtection;
+ Section.Segment = NULL;
+ Section.SizeOfSection.QuadPart = NewSegment->SizeOfSegment;
+ Section.Segment = NewSegment;
+
+ /* THe mapping created a control area and segment, save the flags */
+ ControlArea = NewSegment->ControlArea;
+ Section.u.LongFlags = ControlArea->u.LongFlags;
+
+ /* ARM3 cannot support these right now, make sure they're not being set */
+ ASSERT(ControlArea->u.Flags.Image == 0);
+ ASSERT(ControlArea->FilePointer == NULL);
+ ASSERT(ControlArea->u.Flags.GlobalOnlyPerSession == 0);
+ ASSERT(ControlArea->u.Flags.Rom == 0);
+ ASSERT(ControlArea->u.Flags.WasPurged == 0);
+
+ /* A pagefile-backed mapping only has one subsection, and this is all ARM3 supports */
+ Subsection = (PSUBSECTION)(ControlArea + 1);
+ ASSERT(Subsection->NextSubsection == NULL);
+
+ /* Create the actual section object, with enough space for the prototype PTEs */
+ Status = ObCreateObject(ExGetPreviousMode(),
+ MmSectionObjectType,
+ ObjectAttributes,
+ ExGetPreviousMode(),
+ NULL,
+ sizeof(SECTION),
+ sizeof(SECTION) +
+ NewSegment->TotalNumberOfPtes * sizeof(MMPTE),
+ sizeof(CONTROL_AREA) + sizeof(SUBSECTION),
+ (PVOID*)&NewSection);
+ ASSERT(NT_SUCCESS(Status));
+
+ /* Now copy the local section object from the stack into this new object */
+ RtlCopyMemory(NewSection, &Section, sizeof(SECTION));
+ NewSection->Address.StartingVpn = 0;
+
+ /* Return the object and the creation status */
+ *SectionObject = (PVOID)NewSection;
+ return Status;
}
/* SYSTEM CALLS ***************************************************************/
Author: sir_richard
Date: Mon Oct 4 18:51:07 2010
New Revision: 48979
URL: http://svn.reactos.org/svn/reactos?rev=48979&view=rev
Log:
[NTOS]: Implement/fixup the code paths during page faults that are needed to succesfuly resolve a demand page associated with a pagefile backed ARM3 section (which uses Prototype PTEs). A lot of the code was already there but assumed we were using Prototype PTEs only for the shared user data page. By combining that code with the typical demand-zero fault code, we obtain the needed paths. For now, only tested with ARM3 sections that are page-filed backed (not image or data-file backed) mapped into system view space (MmMapViewOfSectionInSystemSpace), not user-mode addresses (which need VADs). The code to actually create/map these doesn't exist in trunk yet, the purpose of this checkin is to test the new fault changes to make sure they don't cause negative effects to already-working faults.
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] Mon Oct 4 18:51:07 2010
@@ -176,15 +176,14 @@
{
PFN_NUMBER PageFrameNumber = 0;
MMPTE TempPte;
- BOOLEAN NeedZero = FALSE;
+ BOOLEAN NeedZero = FALSE, HaveLock = FALSE;
ULONG Color;
DPRINT("ARM3 Demand Zero Page Fault Handler for address: %p in process: %p\n",
Address,
Process);
/* Must currently only be called by paging path */
- ASSERT(OldIrql == MM_NOIRQL);
- if (Process)
+ if ((Process) && (OldIrql == MM_NOIRQL))
{
/* Sanity check */
ASSERT(MI_IS_PAGE_TABLE_ADDRESS(PointerPte));
@@ -194,45 +193,64 @@
/* Get process color */
Color = MI_GET_NEXT_PROCESS_COLOR(Process);
+ ASSERT(Color != 0xFFFFFFFF);
/* We'll need a zero page */
NeedZero = TRUE;
}
else
{
+ /* Check if we need a zero page */
+ NeedZero = (OldIrql != MM_NOIRQL);
+
/* Get the next system page color */
Color = MI_GET_NEXT_COLOR();
}
-
- //
- // Lock the PFN database
- //
- OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Check if the PFN database should be acquired */
+ if (OldIrql == MM_NOIRQL)
+ {
+ /* Acquire it and remember we should release it after */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+ HaveLock = TRUE;
+ }
+
+ /* 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);
-
- /* Do we need a zero page? */
- if (NeedZero)
+ if ((NeedZero) && (Process))
{
/* Try to get one, if we couldn't grab a free page and zero it */
PageFrameNumber = MiRemoveZeroPageSafe(Color);
- if (PageFrameNumber) NeedZero = FALSE;
- }
-
- /* Did we get a page? */
- if (!PageFrameNumber)
- {
- /* We either failed to find a zero page, or this is a system request */
+ if (PageFrameNumber)
+ {
+ /* We got a genuine zero page, stop worrying about it */
+ NeedZero = FALSE;
+ }
+ else
+ {
+ /* 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);
- DPRINT("New pool page: %lx\n", PageFrameNumber);
+ }
+ else
+ {
+ /* System wants a zero page, obtain one */
+ PageFrameNumber = MiRemoveZeroPage(Color);
}
/* Initialize it */
MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
- //
- // Release PFN lock
- //
- KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ /* Release PFN lock if needed */
+ if (HaveLock) KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
//
// Increment demand zero faults
@@ -283,24 +301,53 @@
IN PMMPFN Pfn1)
{
MMPTE TempPte;
+ PMMPTE OriginalPte;
+ ULONG Protection;
PFN_NUMBER PageFrameIndex;
/* Must be called with an valid prototype PTE, with the PFN lock held */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
ASSERT(PointerProtoPte->u.Hard.Valid == 1);
- /* Quick-n-dirty */
- ASSERT(PointerPte->u.Soft.PageFileHigh == 0xFFFFF);
-
/* Get the page */
PageFrameIndex = PFN_FROM_PTE(PointerProtoPte);
+
+ /* Get the PFN entry and set it as a prototype PTE */
+ Pfn1 = MiGetPfnEntry(PageFrameIndex);
+ Pfn1->u3.e1.PrototypePte = 1;
+
+ /* FIXME: Increment the share count for the page table */
+
+ /* Check where we should be getting the protection information from */
+ if (PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED)
+ {
+ /* Get the protection from the PTE, there's no real Proto PTE data */
+ Protection = PointerPte->u.Soft.Protection;
+ }
+ else
+ {
+ /* Get the protection from the original PTE link */
+ OriginalPte = &Pfn1->OriginalPte;
+ Protection = OriginalPte->u.Soft.Protection;
+ }
/* Release the PFN lock */
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
- /* Build the user PTE */
- ASSERT(Address < MmSystemRangeStart);
- MI_MAKE_HARDWARE_PTE_USER(&TempPte, PointerPte, MM_READONLY, PageFrameIndex);
+ /* Remove caching bits */
+ Protection &= ~(MM_NOCACHE | MM_NOACCESS);
+
+ /* Check if this is a kernel or user address */
+ if (Address < MmSystemRangeStart)
+ {
+ /* Build the user PTE */
+ MI_MAKE_HARDWARE_PTE_USER(&TempPte, PointerPte, Protection, PageFrameIndex);
+ }
+ else
+ {
+ /* Build the kernel PTE */
+ MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, PageFrameIndex);
+ }
/* Write the PTE */
MI_WRITE_VALID_PTE(PointerPte, TempPte);
@@ -325,25 +372,56 @@
MMPTE TempPte;
PMMPFN Pfn1;
PFN_NUMBER PageFrameIndex;
+ NTSTATUS Status;
/* Must be called with an invalid, prototype PTE, with the PFN lock held */
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
ASSERT(PointerPte->u.Hard.Valid == 0);
ASSERT(PointerPte->u.Soft.Prototype == 1);
- /* Read the prototype PTE -- it must be valid since we only handle shared data */
+ /* Read the prototype PTE and check if it's valid */
TempPte = *PointerProtoPte;
- ASSERT(TempPte.u.Hard.Valid == 1);
-
- /* One more user of this mapped page */
- PageFrameIndex = PFN_FROM_PTE(&TempPte);
- Pfn1 = MiGetPfnEntry(PageFrameIndex);
- Pfn1->u2.ShareCount++;
-
- /* Call it a transition */
- InterlockedIncrement(&KeGetCurrentPrcb()->MmTransitionCount);
+ if (TempPte.u.Hard.Valid == 1)
+ {
+ /* One more user of this mapped page */
+ PageFrameIndex = PFN_FROM_PTE(&TempPte);
+ Pfn1 = MiGetPfnEntry(PageFrameIndex);
+ Pfn1->u2.ShareCount++;
+
+ /* Call it a transition */
+ InterlockedIncrement(&KeGetCurrentPrcb()->MmTransitionCount);
+
+ /* Complete the prototype PTE fault -- this will release the PFN lock */
+ return MiCompleteProtoPteFault(StoreInstruction,
+ Address,
+ PointerPte,
+ PointerProtoPte,
+ OldIrql,
+ NULL);
+ }
+
+ /* Make sure there's some protection mask */
+ if (TempPte.u.Long == 0)
+ {
+ /* Release the lock */
+ DPRINT1("Access on reserved section?\n");
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+ return STATUS_ACCESS_VIOLATION;
+ }
+
+ /* This is the only thing we support right now */
+ ASSERT(TempPte.u.Soft.PageFileHigh == 0);
+ ASSERT(TempPte.u.Proto.ReadOnly == 0);
+ ASSERT(PointerPte > MiHighestUserPte);
+ ASSERT(TempPte.u.Soft.Prototype == 0);
+ ASSERT(TempPte.u.Soft.Transition == 0);
+
+ /* Resolve the demand zero fault */
+ Status = MiResolveDemandZeroFault(Address, PointerProtoPte, Process, OldIrql);
+ ASSERT(NT_SUCCESS(Status));
/* Complete the prototype PTE fault -- this will release the PFN lock */
+ ASSERT(PointerPte->u.Hard.Valid == 0);
return MiCompleteProtoPteFault(StoreInstruction,
Address,
PointerPte,
@@ -388,39 +466,76 @@
{
/* This should never happen */
ASSERT(!MI_IS_PHYSICAL_ADDRESS(PointerProtoPte));
+
+ /* Check if this is a kernel-mode address */
+ SuperProtoPte = MiAddressToPte(PointerProtoPte);
+ if (Address >= MmSystemRangeStart)
+ {
+ /* Lock the PFN database */
+ LockIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
- /* We currently only handle the shared user data PTE path */
- ASSERT(Address < MmSystemRangeStart);
- ASSERT(PointerPte->u.Soft.Prototype == 1);
- ASSERT(PointerPte->u.Soft.PageFileHigh == 0xFFFFF);
- ASSERT(Vad == NULL);
-
- /* Lock the PFN database */
- LockIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-
- /* For the shared data page, this should be true */
- SuperProtoPte = MiAddressToPte(PointerProtoPte);
- ASSERT(SuperProtoPte->u.Hard.Valid == 1);
- ASSERT(TempPte.u.Hard.Valid == 0);
-
- /* 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_PAGE_FAULT_TRANSITION;
+ /* Has the PTE been made valid yet? */
+ if (!SuperProtoPte->u.Hard.Valid)
+ {
+ UNIMPLEMENTED;
+ while (TRUE);
+ }
+ else
+ {
+ ASSERT(PointerPte->u.Hard.Valid == 0);
+ /* 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
+ {
+ /* We currently only handle the shared user data PTE path */
+ ASSERT(PointerPte->u.Soft.Prototype == 1);
+ ASSERT(PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED);
+ ASSERT(Vad == NULL);
+
+ /* Lock the PFN database */
+ LockIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* For the shared data page, this should be true */
+ ASSERT(SuperProtoPte->u.Hard.Valid == 1);
+ ASSERT(TempPte.u.Hard.Valid == 0);
+
+ /* 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_PAGE_FAULT_TRANSITION;
+ }
}
//
@@ -469,7 +584,7 @@
IN PVOID TrapInformation)
{
KIRQL OldIrql = KeGetCurrentIrql(), LockIrql;
- PMMPTE PointerPte, ProtoPte;
+ PMMPTE PointerPte, ProtoPte = NULL;
PMMPDE PointerPde;
MMPTE TempPte;
PETHREAD CurrentThread;
@@ -645,9 +760,6 @@
/* Check one kind of prototype PTE */
if (TempPte.u.Soft.Prototype)
{
- /* The one used for protected pool... */
- ASSERT(MmProtectFreedNonPagedPool == TRUE);
-
/* Make sure protected pool is on, and that this is a pool address */
if ((MmProtectFreedNonPagedPool) &&
(((Address >= MmNonPagedPoolStart) &&
@@ -663,12 +775,41 @@
Mode,
4);
}
+
+ /* Get the prototype PTE! */
+ ProtoPte = MiProtoPteToPte(&TempPte);
}
//
// We don't implement transition PTEs
//
ASSERT(TempPte.u.Soft.Transition == 0);
+
+ /* Check for no-access PTE */
+ if (TempPte.u.Soft.Protection == MM_NOACCESS)
+ {
+ /* Bad boy, bad boy, whatcha gonna do, whatcha gonna do when ARM3 comes for you! */
+ KeBugCheckEx(PAGE_FAULT_IN_NONPAGED_AREA,
+ (ULONG_PTR)Address,
+ StoreInstruction,
+ (ULONG_PTR)TrapInformation,
+ 1);
+ }
+
+ /* Check for demand page */
+ if ((StoreInstruction) && !(ProtoPte) && !(TempPte.u.Hard.Valid))
+ {
+ /* Get the protection code */
+ if (!(TempPte.u.Soft.Protection & MM_READWRITE))
+ {
+ /* Bad boy, bad boy, whatcha gonna do, whatcha gonna do when ARM3 comes for you! */
+ KeBugCheckEx(ATTEMPTED_WRITE_TO_READONLY_MEMORY,
+ (ULONG_PTR)Address,
+ TempPte.u.Long,
+ (ULONG_PTR)TrapInformation,
+ 14);
+ }
+ }
//
// Now do the real fault handling
@@ -676,7 +817,7 @@
Status = MiDispatchFault(StoreInstruction,
Address,
PointerPte,
- NULL,
+ ProtoPte,
FALSE,
NULL,
TrapInformation,
Author: sir_richard
Date: Mon Oct 4 18:34:41 2010
New Revision: 48977
URL: http://svn.reactos.org/svn/reactos?rev=48977&view=rev
Log:
[NTOS]: Define MI_MAKE_PROTOTYPE_PTE macro to make a real prototype PTE from a PTE. Define counter-part MiProtoPteToPte to recover the true PTE from a given Prototype PTE.
[NTOS]: Define MI_PTE_LOOKUP_NEEDED instead of using 0xFFFF. The name was found in checked build assertion strings.
[NTOS]: Add MM_VIEW (used for System-mapped Section Views) and MM_SESSSION (used to define the system/session view mappings) structure definitions.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/i386/init.c
trunk/reactos/ntoskrnl/mm/ARM3/miarm.h
Modified: trunk/reactos/ntoskrnl/mm/ARM3/i386/init.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/i386/init…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/i386/init.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/i386/init.c [iso-8859-1] Mon Oct 4 18:34:41 2010
@@ -26,7 +26,7 @@
MMPDE DemandZeroPde = {.u.Long = (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS)};
/* Template PTE for prototype page */
-MMPTE PrototypePte = {.u.Long = (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS) | PTE_PROTOTYPE | 0xFFFFF000};
+MMPTE PrototypePte = {.u.Long = (MM_READWRITE << MM_PTE_SOFTWARE_PROTECTION_BITS) | PTE_PROTOTYPE | (MI_PTE_LOOKUP_NEEDED << PAGE_SHIFT)};
/* PRIVATE FUNCTIONS **********************************************************/
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] Mon Oct 4 18:34:41 2010
@@ -232,6 +232,18 @@
#define MI_GET_PAGE_COLOR(x) ((x) & MmSecondaryColorMask)
#define MI_GET_NEXT_COLOR(x) (MI_GET_PAGE_COLOR(++MmSystemPageColor))
#define MI_GET_NEXT_PROCESS_COLOR(x) (MI_GET_PAGE_COLOR(++(x)->NextPageColor))
+
+//
+// Decodes a Prototype PTE into the underlying PTE
+//
+#define MiProtoPteToPte(x) \
+ (PMMPTE)((ULONG_PTR)MmPagedPoolStart + \
+ ((x)->u.Proto.ProtoAddressHigh | (x)->u.Proto.ProtoAddressLow))
+
+//
+// Prototype PTEs that don't yet have a pagefile association
+//
+#define MI_PTE_LOOKUP_NEEDED 0xFFFFF
//
// FIXFIX: These should go in ex.h after the pool merge
@@ -358,6 +370,25 @@
PFN_NUMBER StartFrame;
PFN_NUMBER LastFrame;
} MI_LARGE_PAGE_RANGES, *PMI_LARGE_PAGE_RANGES;
+
+typedef struct _MMVIEW
+{
+ ULONG_PTR Entry;
+ PCONTROL_AREA ControlArea;
+} MMVIEW, *PMMVIEW;
+
+typedef struct _MMSESSION
+{
+ KGUARDED_MUTEX SystemSpaceViewLock;
+ PKGUARDED_MUTEX SystemSpaceViewLockPointer;
+ PCHAR SystemSpaceViewStart;
+ PMMVIEW SystemSpaceViewTable;
+ ULONG SystemSpaceHashSize;
+ ULONG SystemSpaceHashEntries;
+ ULONG SystemSpaceHashKey;
+ ULONG BitmapFailures;
+ PRTL_BITMAP SystemSpaceBitMap;
+} MMSESSION, *PMMSESSION;
extern MMPTE HyperTemplatePte;
extern MMPDE ValidKernelPde;
@@ -565,6 +596,31 @@
}
//
+// Builds a Prototype PTE for the address of the PTE
+//
+FORCEINLINE
+VOID
+MI_MAKE_PROTOTYPE_PTE(IN PMMPTE NewPte,
+ IN PMMPTE PointerPte)
+{
+ ULONG_PTR Offset;
+
+ /* Mark this as a prototype */
+ NewPte->u.Long = 0;
+ NewPte->u.Proto.Prototype = 1;
+
+ /*
+ * Prototype PTEs are only valid in paged pool by design, this little trick
+ * lets us only use 28 bits for the adress of the PTE
+ */
+ Offset = (ULONG_PTR)PointerPte - (ULONG_PTR)MmPagedPoolStart;
+
+ /* 7 bits go in the "low", and the other 21 bits go in the "high" */
+ NewPte->u.Proto.ProtoAddressLow = Offset & 0x7F;
+ NewPte->u.Proto.ProtoAddressHigh = Offset & 0xFFFFF80;
+}
+
+//
// Returns if the page is physically resident (ie: a large page)
// FIXFIX: CISC/x86 only?
//
@@ -1107,6 +1163,12 @@
IN PMMADDRESS_NODE Node
);
+BOOLEAN
+NTAPI
+MiInitializeSystemSpaceMap(
+ IN PVOID InputSession OPTIONAL
+);
+
//
// MiRemoveZeroPage will use inline code to zero out the page manually if only
// free pages are available. In some scenarios, we don't/can't run that piece of
Author: sir_richard
Date: Mon Oct 4 18:22:50 2010
New Revision: 48976
URL: http://svn.reactos.org/svn/reactos?rev=48976&view=rev
Log:
[NTOS]: Go ahead and now fill out the OriginalPte field for PFNs initialized with MiInitializePfn(ForOtherProcess). They should only belong to ARM3 so they'll never have SwapEntry/RMAP associated with them. This functionality is important for future Prototype PTE support, among other things, as it lets us get the original PTE value written for a given PFN entry.
Modified:
trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c
Modified: trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c…
==============================================================================
--- trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/mm/ARM3/pfnlist.c [iso-8859-1] Mon Oct 4 18:22:50 2010
@@ -713,6 +713,16 @@
{
/* Only valid from MmCreateProcessAddressSpace path */
ASSERT(PsGetCurrentProcess()->Vm.WorkingSetSize == 0);
+
+ /* Make this a demand zero PTE */
+ MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
+ }
+ else
+ {
+ /* Copy the PTE data */
+ Pfn1->OriginalPte = *PointerPte;
+ ASSERT(!((Pfn1->OriginalPte.u.Soft.Prototype == 0) &&
+ (Pfn1->OriginalPte.u.Soft.Transition == 1)));
}
/* Otherwise this is a fresh page -- set it up */
@@ -870,11 +880,9 @@
/* Setup the PTE */
Pfn1 = MiGetPfnEntry(PageFrameIndex);
Pfn1->PteAddress = PointerPte;
-
-#if 0 // When using ARM3 PFN
+
/* Make this a software PTE */
MI_MAKE_SOFTWARE_PTE(&Pfn1->OriginalPte, MM_READWRITE);
-#endif
/* Setup the page */
ASSERT(Pfn1->u3.e2.ReferenceCount == 0);