mirror of
https://github.com/reactos/reactos.git
synced 2024-07-14 08:26:08 +00:00
[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.
svn path=/trunk/; revision=48979
This commit is contained in:
parent
9dc0c0d12a
commit
5518b60eac
|
@ -176,15 +176,14 @@ MiResolveDemandZeroFault(IN PVOID Address,
|
|||
{
|
||||
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 @@ MiResolveDemandZeroFault(IN PVOID Address,
|
|||
|
||||
/* 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
|
||||
//
|
||||
/* Check if the PFN database should be acquired */
|
||||
if (OldIrql == MM_NOIRQL)
|
||||
{
|
||||
/* Acquire it and remember we should release it after */
|
||||
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
|
||||
ASSERT(PointerPte->u.Hard.Valid == 0);
|
||||
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? */
|
||||
if (NeedZero)
|
||||
ASSERT(PointerPte->u.Hard.Valid == 0);
|
||||
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)
|
||||
if (PageFrameNumber)
|
||||
{
|
||||
/* We either failed to find a zero page, or this is a system request */
|
||||
/* 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);
|
||||
DPRINT("New pool page: %lx\n", PageFrameNumber);
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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 @@ MiCompleteProtoPteFault(IN BOOLEAN StoreInstruction,
|
|||
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);
|
||||
|
||||
/* Remove caching bits */
|
||||
Protection &= ~(MM_NOCACHE | MM_NOACCESS);
|
||||
|
||||
/* Check if this is a kernel or user address */
|
||||
if (Address < MmSystemRangeStart)
|
||||
{
|
||||
/* Build the user PTE */
|
||||
ASSERT(Address < MmSystemRangeStart);
|
||||
MI_MAKE_HARDWARE_PTE_USER(&TempPte, PointerPte, MM_READONLY, PageFrameIndex);
|
||||
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,16 +372,17 @@ MiResolveProtoPteFault(IN BOOLEAN StoreInstruction,
|
|||
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);
|
||||
|
||||
if (TempPte.u.Hard.Valid == 1)
|
||||
{
|
||||
/* One more user of this mapped page */
|
||||
PageFrameIndex = PFN_FROM_PTE(&TempPte);
|
||||
Pfn1 = MiGetPfnEntry(PageFrameIndex);
|
||||
|
@ -350,6 +398,36 @@ MiResolveProtoPteFault(IN BOOLEAN StoreInstruction,
|
|||
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,
|
||||
PointerProtoPte,
|
||||
OldIrql,
|
||||
NULL);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
|
@ -389,17 +467,53 @@ MiDispatchFault(IN BOOLEAN StoreInstruction,
|
|||
/* 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);
|
||||
|
||||
/* 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(Address < MmSystemRangeStart);
|
||||
ASSERT(PointerPte->u.Soft.Prototype == 1);
|
||||
ASSERT(PointerPte->u.Soft.PageFileHigh == 0xFFFFF);
|
||||
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 */
|
||||
SuperProtoPte = MiAddressToPte(PointerProtoPte);
|
||||
ASSERT(SuperProtoPte->u.Hard.Valid == 1);
|
||||
ASSERT(TempPte.u.Hard.Valid == 0);
|
||||
|
||||
|
@ -422,6 +536,7 @@ MiDispatchFault(IN BOOLEAN StoreInstruction,
|
|||
ASSERT(KeAreAllApcsDisabled() == TRUE);
|
||||
return STATUS_PAGE_FAULT_TRANSITION;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// The PTE must be invalid, but not totally blank
|
||||
|
@ -469,7 +584,7 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
|
|||
IN PVOID TrapInformation)
|
||||
{
|
||||
KIRQL OldIrql = KeGetCurrentIrql(), LockIrql;
|
||||
PMMPTE PointerPte, ProtoPte;
|
||||
PMMPTE PointerPte, ProtoPte = NULL;
|
||||
PMMPDE PointerPde;
|
||||
MMPTE TempPte;
|
||||
PETHREAD CurrentThread;
|
||||
|
@ -645,9 +760,6 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
|
|||
/* 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,6 +775,9 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
|
|||
Mode,
|
||||
4);
|
||||
}
|
||||
|
||||
/* Get the prototype PTE! */
|
||||
ProtoPte = MiProtoPteToPte(&TempPte);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -670,13 +785,39 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
|
|||
//
|
||||
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
|
||||
//
|
||||
Status = MiDispatchFault(StoreInstruction,
|
||||
Address,
|
||||
PointerPte,
|
||||
NULL,
|
||||
ProtoPte,
|
||||
FALSE,
|
||||
NULL,
|
||||
TrapInformation,
|
||||
|
|
Loading…
Reference in a new issue