mirror of
https://github.com/reactos/reactos.git
synced 2024-09-11 05:12:43 +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;
|
PFN_NUMBER PageFrameNumber = 0;
|
||||||
MMPTE TempPte;
|
MMPTE TempPte;
|
||||||
BOOLEAN NeedZero = FALSE;
|
BOOLEAN NeedZero = FALSE, HaveLock = FALSE;
|
||||||
ULONG Color;
|
ULONG Color;
|
||||||
DPRINT("ARM3 Demand Zero Page Fault Handler for address: %p in process: %p\n",
|
DPRINT("ARM3 Demand Zero Page Fault Handler for address: %p in process: %p\n",
|
||||||
Address,
|
Address,
|
||||||
Process);
|
Process);
|
||||||
|
|
||||||
/* Must currently only be called by paging path */
|
/* Must currently only be called by paging path */
|
||||||
ASSERT(OldIrql == MM_NOIRQL);
|
if ((Process) && (OldIrql == MM_NOIRQL))
|
||||||
if (Process)
|
|
||||||
{
|
{
|
||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
ASSERT(MI_IS_PAGE_TABLE_ADDRESS(PointerPte));
|
ASSERT(MI_IS_PAGE_TABLE_ADDRESS(PointerPte));
|
||||||
|
@ -194,45 +193,64 @@ MiResolveDemandZeroFault(IN PVOID Address,
|
||||||
|
|
||||||
/* Get process color */
|
/* Get process color */
|
||||||
Color = MI_GET_NEXT_PROCESS_COLOR(Process);
|
Color = MI_GET_NEXT_PROCESS_COLOR(Process);
|
||||||
|
ASSERT(Color != 0xFFFFFFFF);
|
||||||
|
|
||||||
/* We'll need a zero page */
|
/* We'll need a zero page */
|
||||||
NeedZero = TRUE;
|
NeedZero = TRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
/* Check if we need a zero page */
|
||||||
|
NeedZero = (OldIrql != MM_NOIRQL);
|
||||||
|
|
||||||
/* Get the next system page color */
|
/* Get the next system page color */
|
||||||
Color = MI_GET_NEXT_COLOR();
|
Color = MI_GET_NEXT_COLOR();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
/* Check if the PFN database should be acquired */
|
||||||
// Lock the PFN database
|
if (OldIrql == MM_NOIRQL)
|
||||||
//
|
{
|
||||||
|
/* Acquire it and remember we should release it after */
|
||||||
OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
|
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? */
|
/* 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 */
|
/* Try to get one, if we couldn't grab a free page and zero it */
|
||||||
PageFrameNumber = MiRemoveZeroPageSafe(Color);
|
PageFrameNumber = MiRemoveZeroPageSafe(Color);
|
||||||
if (PageFrameNumber) NeedZero = FALSE;
|
if (PageFrameNumber)
|
||||||
}
|
|
||||||
|
|
||||||
/* Did we get a page? */
|
|
||||||
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);
|
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 */
|
/* Initialize it */
|
||||||
MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
|
MiInitializePfn(PageFrameNumber, PointerPte, TRUE);
|
||||||
|
|
||||||
//
|
/* Release PFN lock if needed */
|
||||||
// Release PFN lock
|
if (HaveLock) KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
|
||||||
//
|
|
||||||
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Increment demand zero faults
|
// Increment demand zero faults
|
||||||
|
@ -283,24 +301,53 @@ MiCompleteProtoPteFault(IN BOOLEAN StoreInstruction,
|
||||||
IN PMMPFN Pfn1)
|
IN PMMPFN Pfn1)
|
||||||
{
|
{
|
||||||
MMPTE TempPte;
|
MMPTE TempPte;
|
||||||
|
PMMPTE OriginalPte;
|
||||||
|
ULONG Protection;
|
||||||
PFN_NUMBER PageFrameIndex;
|
PFN_NUMBER PageFrameIndex;
|
||||||
|
|
||||||
/* Must be called with an valid prototype PTE, with the PFN lock held */
|
/* Must be called with an valid prototype PTE, with the PFN lock held */
|
||||||
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||||||
ASSERT(PointerProtoPte->u.Hard.Valid == 1);
|
ASSERT(PointerProtoPte->u.Hard.Valid == 1);
|
||||||
|
|
||||||
/* Quick-n-dirty */
|
|
||||||
ASSERT(PointerPte->u.Soft.PageFileHigh == 0xFFFFF);
|
|
||||||
|
|
||||||
/* Get the page */
|
/* Get the page */
|
||||||
PageFrameIndex = PFN_FROM_PTE(PointerProtoPte);
|
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 */
|
/* Release the PFN lock */
|
||||||
KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
|
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 */
|
/* Build the user PTE */
|
||||||
ASSERT(Address < MmSystemRangeStart);
|
MI_MAKE_HARDWARE_PTE_USER(&TempPte, PointerPte, Protection, PageFrameIndex);
|
||||||
MI_MAKE_HARDWARE_PTE_USER(&TempPte, PointerPte, MM_READONLY, PageFrameIndex);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Build the kernel PTE */
|
||||||
|
MI_MAKE_HARDWARE_PTE(&TempPte, PointerPte, Protection, PageFrameIndex);
|
||||||
|
}
|
||||||
|
|
||||||
/* Write the PTE */
|
/* Write the PTE */
|
||||||
MI_WRITE_VALID_PTE(PointerPte, TempPte);
|
MI_WRITE_VALID_PTE(PointerPte, TempPte);
|
||||||
|
@ -325,16 +372,17 @@ MiResolveProtoPteFault(IN BOOLEAN StoreInstruction,
|
||||||
MMPTE TempPte;
|
MMPTE TempPte;
|
||||||
PMMPFN Pfn1;
|
PMMPFN Pfn1;
|
||||||
PFN_NUMBER PageFrameIndex;
|
PFN_NUMBER PageFrameIndex;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
/* Must be called with an invalid, prototype PTE, with the PFN lock held */
|
/* Must be called with an invalid, prototype PTE, with the PFN lock held */
|
||||||
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||||||
ASSERT(PointerPte->u.Hard.Valid == 0);
|
ASSERT(PointerPte->u.Hard.Valid == 0);
|
||||||
ASSERT(PointerPte->u.Soft.Prototype == 1);
|
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;
|
TempPte = *PointerProtoPte;
|
||||||
ASSERT(TempPte.u.Hard.Valid == 1);
|
if (TempPte.u.Hard.Valid == 1)
|
||||||
|
{
|
||||||
/* One more user of this mapped page */
|
/* One more user of this mapped page */
|
||||||
PageFrameIndex = PFN_FROM_PTE(&TempPte);
|
PageFrameIndex = PFN_FROM_PTE(&TempPte);
|
||||||
Pfn1 = MiGetPfnEntry(PageFrameIndex);
|
Pfn1 = MiGetPfnEntry(PageFrameIndex);
|
||||||
|
@ -352,6 +400,36 @@ MiResolveProtoPteFault(IN BOOLEAN StoreInstruction,
|
||||||
NULL);
|
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
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
MiDispatchFault(IN BOOLEAN StoreInstruction,
|
MiDispatchFault(IN BOOLEAN StoreInstruction,
|
||||||
|
@ -389,17 +467,53 @@ MiDispatchFault(IN BOOLEAN StoreInstruction,
|
||||||
/* This should never happen */
|
/* This should never happen */
|
||||||
ASSERT(!MI_IS_PHYSICAL_ADDRESS(PointerProtoPte));
|
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 */
|
/* We currently only handle the shared user data PTE path */
|
||||||
ASSERT(Address < MmSystemRangeStart);
|
|
||||||
ASSERT(PointerPte->u.Soft.Prototype == 1);
|
ASSERT(PointerPte->u.Soft.Prototype == 1);
|
||||||
ASSERT(PointerPte->u.Soft.PageFileHigh == 0xFFFFF);
|
ASSERT(PointerPte->u.Soft.PageFileHigh == MI_PTE_LOOKUP_NEEDED);
|
||||||
ASSERT(Vad == NULL);
|
ASSERT(Vad == NULL);
|
||||||
|
|
||||||
/* Lock the PFN database */
|
/* Lock the PFN database */
|
||||||
LockIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
|
LockIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
|
||||||
|
|
||||||
/* For the shared data page, this should be true */
|
/* For the shared data page, this should be true */
|
||||||
SuperProtoPte = MiAddressToPte(PointerProtoPte);
|
|
||||||
ASSERT(SuperProtoPte->u.Hard.Valid == 1);
|
ASSERT(SuperProtoPte->u.Hard.Valid == 1);
|
||||||
ASSERT(TempPte.u.Hard.Valid == 0);
|
ASSERT(TempPte.u.Hard.Valid == 0);
|
||||||
|
|
||||||
|
@ -422,6 +536,7 @@ MiDispatchFault(IN BOOLEAN StoreInstruction,
|
||||||
ASSERT(KeAreAllApcsDisabled() == TRUE);
|
ASSERT(KeAreAllApcsDisabled() == TRUE);
|
||||||
return STATUS_PAGE_FAULT_TRANSITION;
|
return STATUS_PAGE_FAULT_TRANSITION;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// The PTE must be invalid, but not totally blank
|
// The PTE must be invalid, but not totally blank
|
||||||
|
@ -469,7 +584,7 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
|
||||||
IN PVOID TrapInformation)
|
IN PVOID TrapInformation)
|
||||||
{
|
{
|
||||||
KIRQL OldIrql = KeGetCurrentIrql(), LockIrql;
|
KIRQL OldIrql = KeGetCurrentIrql(), LockIrql;
|
||||||
PMMPTE PointerPte, ProtoPte;
|
PMMPTE PointerPte, ProtoPte = NULL;
|
||||||
PMMPDE PointerPde;
|
PMMPDE PointerPde;
|
||||||
MMPTE TempPte;
|
MMPTE TempPte;
|
||||||
PETHREAD CurrentThread;
|
PETHREAD CurrentThread;
|
||||||
|
@ -645,9 +760,6 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
|
||||||
/* Check one kind of prototype PTE */
|
/* Check one kind of prototype PTE */
|
||||||
if (TempPte.u.Soft.Prototype)
|
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 */
|
/* Make sure protected pool is on, and that this is a pool address */
|
||||||
if ((MmProtectFreedNonPagedPool) &&
|
if ((MmProtectFreedNonPagedPool) &&
|
||||||
(((Address >= MmNonPagedPoolStart) &&
|
(((Address >= MmNonPagedPoolStart) &&
|
||||||
|
@ -663,6 +775,9 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
|
||||||
Mode,
|
Mode,
|
||||||
4);
|
4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the prototype PTE! */
|
||||||
|
ProtoPte = MiProtoPteToPte(&TempPte);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -670,13 +785,39 @@ MmArmAccessFault(IN BOOLEAN StoreInstruction,
|
||||||
//
|
//
|
||||||
ASSERT(TempPte.u.Soft.Transition == 0);
|
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
|
// Now do the real fault handling
|
||||||
//
|
//
|
||||||
Status = MiDispatchFault(StoreInstruction,
|
Status = MiDispatchFault(StoreInstruction,
|
||||||
Address,
|
Address,
|
||||||
PointerPte,
|
PointerPte,
|
||||||
NULL,
|
ProtoPte,
|
||||||
FALSE,
|
FALSE,
|
||||||
NULL,
|
NULL,
|
||||||
TrapInformation,
|
TrapInformation,
|
||||||
|
|
Loading…
Reference in a new issue