Author: tkreuzer
Date: Fri Jul 23 01:36:44 2010
New Revision: 48206
URL: http://svn.reactos.org/svn/reactos?rev=48206&view=rev
Log:
[PSEH]
Add (non working) 64bit code
Added:
trunk/reactos/lib/pseh/amd64/ (with props)
trunk/reactos/lib/pseh/amd64/framebased.S (with props)
Modified:
trunk/reactos/lib/pseh/pseh.rbuild
Propchange: trunk/reactos/lib/pseh/amd64/
------------------------------------------------------------------------------
--- bugtraq:logregex (added)
+++ bugtraq:logregex Fri Jul 23 01:36:44 2010
@@ -1,0 +1,2 @@
+([Ii]ssue|[Bb]ug)s? #?(\d+)(,? ?#?(\d+))*(,? ?(and |or )?#?(\d+))?
+(\d+)
Propchange: trunk/reactos/lib/pseh/amd64/
------------------------------------------------------------------------------
bugtraq:message = See issue #%BUGID% for more details.
Propchange: trunk/reactos/lib/pseh/amd64/
------------------------------------------------------------------------------
bugtraq:url = http://www.reactos.org/bugzilla/show_bug.cgi?id=%BUGID%
Propchange: trunk/reactos/lib/pseh/amd64/
------------------------------------------------------------------------------
tsvn:logminsize = 10
Added: trunk/reactos/lib/pseh/amd64/framebased.S
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/pseh/amd64/framebased.…
==============================================================================
--- trunk/reactos/lib/pseh/amd64/framebased.S (added)
+++ trunk/reactos/lib/pseh/amd64/framebased.S [iso-8859-1] Fri Jul 23 01:36:44 2010
@@ -1,0 +1,73 @@
+// Copyright (c) 2004/2005 KJK::Hyperion
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to dos so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+.text
+.intel_syntax noprefix
+
+.globl __SEHCleanHandlerEnvironment
+__SEHCleanHandlerEnvironment:
+ cld
+ ret
+
+.globl __SEHCurrentRegistration
+__SEHCurrentRegistration:
+ mov rax, [fs:0]
+ ret
+
+.globl __SEHRegisterFrame
+__SEHRegisterFrame:
+ mov rcx, [rsp+4]
+ mov rax, [fs:0]
+ mov [rcx+0], eax
+ mov [fs:0], ecx
+ ret
+
+.globl __SEHUnregisterFrame
+__SEHUnregisterFrame:
+ mov rcx, [fs:0]
+ mov rcx, [rcx+0]
+ mov [fs:0], rcx
+ ret
+
+.globl __SEHGlobalUnwind
+__SEHGlobalUnwind:
+
+.extern __SEHRtlUnwind
+
+// RtlUnwind clobbers all the "don't clobber" registers, so we save them
+ push rbx
+ mov rbx, [rsp+8]
+ push rsi
+ push rdi
+
+ push 0 // ReturnValue
+ push 0 // ExceptionRecord
+// push .RestoreRegisters // TargetIp
+ push rbx // TargetFrame
+// call [__SEHRtlUnwind]
+
+.RestoreRegisters:
+ pop rdi
+ pop rsi
+ pop rbx
+
+ ret
+
+// EOF
Propchange: trunk/reactos/lib/pseh/amd64/framebased.S
------------------------------------------------------------------------------
svn:eol-style = native
Modified: trunk/reactos/lib/pseh/pseh.rbuild
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/pseh/pseh.rbuild?rev=4…
==============================================================================
--- trunk/reactos/lib/pseh/pseh.rbuild [iso-8859-1] (original)
+++ trunk/reactos/lib/pseh/pseh.rbuild [iso-8859-1] Fri Jul 23 01:36:44 2010
@@ -16,5 +16,10 @@
<file>framebased.S</file>
</directory>
</if>
+ <if property="ARCH" value="amd64">
+ <directory name="amd64">
+ <file>framebased.S</file>
+ </directory>
+ </if>
<file>framebased.c</file>
</module>
Author: sir_richard
Date: Thu Jul 22 20:52:23 2010
New Revision: 48201
URL: http://svn.reactos.org/svn/reactos?rev=48201&view=rev
Log:
Note: this patch only implements the code paths, they are not excercised yet.
[NTOS]: Implement handling a very special case of "prototype PTE", the one used to map the shared user data for user-mode applications.
[NTOS]: MiCheckVirtualAddress detects this (Windows behavior) and returns a prototype PTE that's marked MM_READONLY. This is our MmSharedUserDataPte from before. This gets sent to MiDispatchFault which calls MiResolveProtoPteFault to handle it. In turn, this calls MiCompleteProtoPteFault. All these code paths have heavy ASSERTions to only allow them to be hit for the shared user data page, however, in the far distant future when prototype PTEs are used for section objects, we'll at least have the right checks and code flow (many of these ASSERTions will then have to be removed).
[NTOS]: The end result is that we also now have STATUS_PAGE_FAULT_TRANSITION, not just STATUS_PAGE_FAULT_DEMAND_ZERO, and that prototype PTEs are somewhat understood and some assumptions have been removed.
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] Thu Jul 22 20:52:23 2010
@@ -33,6 +33,14 @@
/* Only valid for user VADs for now */
ASSERT(VirtualAddress <= MM_HIGHEST_USER_ADDRESS);
+
+ /* Special case for shared data */
+ if (PAGE_ALIGN(VirtualAddress) == (PVOID)USER_SHARED_DATA)
+ {
+ /* It's a read-only page */
+ *ProtectCode = MM_READONLY;
+ return MmSharedUserDataPte;
+ }
/* Find the VAD, it must exist, since we only handle PEB/TEB */
Vad = MiLocateAddress(VirtualAddress);
@@ -244,18 +252,98 @@
NTSTATUS
NTAPI
+MiCompleteProtoPteFault(IN BOOLEAN StoreInstruction,
+ IN PVOID Address,
+ IN PMMPTE PointerPte,
+ IN PMMPTE PointerProtoPte,
+ IN KIRQL OldIrql,
+ IN PMMPFN Pfn1)
+{
+ MMPTE TempPte;
+ 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);
+
+ /* Release the PFN lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* Build the user PTE */
+ ASSERT(Address < MmSystemRangeStart);
+ MI_MAKE_HARDWARE_PTE_USER(&TempPte, PointerPte, MM_READONLY, PageFrameIndex);
+
+ /* Write the PTE */
+ MI_WRITE_VALID_PTE(PointerPte, TempPte);
+
+ /* Return success */
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+MiResolveProtoPteFault(IN BOOLEAN StoreInstruction,
+ IN PVOID Address,
+ IN PMMPTE PointerPte,
+ IN PMMPTE PointerProtoPte,
+ IN OUT PMMPFN *OutPfn,
+ OUT PVOID *PageFileData,
+ OUT PMMPTE PteValue,
+ IN PEPROCESS Process,
+ IN KIRQL OldIrql,
+ IN PVOID TrapInformation)
+{
+ MMPTE TempPte;
+ PMMPFN Pfn1;
+ PFN_NUMBER PageFrameIndex;
+
+ /* 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 */
+ 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);
+
+ /* Complete the prototype PTE fault -- this will release the PFN lock */
+ return MiCompleteProtoPteFault(StoreInstruction,
+ Address,
+ PointerPte,
+ PointerProtoPte,
+ OldIrql,
+ NULL);
+}
+
+NTSTATUS
+NTAPI
MiDispatchFault(IN BOOLEAN StoreInstruction,
IN PVOID Address,
IN PMMPTE PointerPte,
- IN PMMPTE PrototypePte,
+ IN PMMPTE PointerProtoPte,
IN BOOLEAN Recursive,
IN PEPROCESS Process,
IN PVOID TrapInformation,
IN PVOID Vad)
{
MMPTE TempPte;
- KIRQL OldIrql;
+ KIRQL OldIrql, LockIrql;
NTSTATUS Status;
+ PMMPTE SuperProtoPte;
DPRINT("ARM3 Page Fault Dispatcher for address: %p in process: %p\n",
Address,
Process);
@@ -263,17 +351,54 @@
//
// Make sure APCs are off and we're not at dispatch
//
- OldIrql = KeGetCurrentIrql ();
+ OldIrql = KeGetCurrentIrql();
ASSERT(OldIrql <= APC_LEVEL);
- ASSERT(KeAreAllApcsDisabled () == TRUE);
+ ASSERT(KeAreAllApcsDisabled() == TRUE);
//
// Grab a copy of the PTE
//
TempPte = *PointerPte;
- /* No prototype */
- ASSERT(PrototypePte == NULL);
+ /* Do we have a prototype PTE? */
+ if (PointerProtoPte)
+ {
+ /* This should never happen */
+ ASSERT(!MI_IS_PHYSICAL_ADDRESS(PointerProtoPte));
+
+ /* 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;
+ }
//
// The PTE must be invalid, but not totally blank
@@ -321,7 +446,7 @@
IN PVOID TrapInformation)
{
KIRQL OldIrql = KeGetCurrentIrql(), LockIrql;
- PMMPTE PointerPte;
+ PMMPTE PointerPte, ProtoPte;
PMMPDE PointerPde;
MMPTE TempPte;
PETHREAD CurrentThread;
@@ -562,64 +687,94 @@
ASSERT(TempPte.u.Long == 0);
/* Check if this address range belongs to a valid allocation (VAD) */
- MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
-
- /* Right now, we expect a valid protection mask on the VAD */
+ ProtoPte = MiCheckVirtualAddress(Address, &ProtectionCode, &Vad);
ASSERT(ProtectionCode != MM_NOACCESS);
- PointerPte->u.Soft.Protection = ProtectionCode;
-
- /* Lock the PFN database since we're going to grab a page */
- OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-
- /* Grab a page out of there. Later we should grab a colored zero page */
- PageFrameIndex = MiRemoveAnyPage(0);
- ASSERT(PageFrameIndex);
-
- /* Release the lock since we need to do some zeroing */
- KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-
- /* Zero out the page, since it's for user-mode */
- MiZeroPfn(PageFrameIndex);
-
- /* Grab the lock again so we can initialize the PFN entry */
- OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
-
- /* Initialize the PFN entry now */
- MiInitializePfn(PageFrameIndex, PointerPte, 1);
-
- /* And we're done with the lock */
- KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
-
- /* One more demand-zero fault */
- InterlockedIncrement(&KeGetCurrentPrcb()->MmDemandZeroCount);
-
- /* Was the fault on an actual user page, or a kernel page for the user? */
- if (PointerPte <= MiHighestUserPte)
- {
- /* User fault, build a user PTE */
- MI_MAKE_HARDWARE_PTE_USER(&TempPte,
- PointerPte,
- PointerPte->u.Soft.Protection,
- PageFrameIndex);
+
+ /* Did we get a prototype PTE back? */
+ if (!ProtoPte)
+ {
+ /* No, create a new PTE. First, write the protection */
+ PointerPte->u.Soft.Protection = ProtectionCode;
+
+ /* Lock the PFN database since we're going to grab a page */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Grab a page out of there. Later we should grab a colored zero page */
+ PageFrameIndex = MiRemoveAnyPage(0);
+ ASSERT(PageFrameIndex);
+
+ /* Release the lock since we need to do some zeroing */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* Zero out the page, since it's for user-mode */
+ MiZeroPfn(PageFrameIndex);
+
+ /* Grab the lock again so we can initialize the PFN entry */
+ OldIrql = KeAcquireQueuedSpinLock(LockQueuePfnLock);
+
+ /* Initialize the PFN entry now */
+ MiInitializePfn(PageFrameIndex, PointerPte, 1);
+
+ /* And we're done with the lock */
+ KeReleaseQueuedSpinLock(LockQueuePfnLock, OldIrql);
+
+ /* One more demand-zero fault */
+ InterlockedIncrement(&KeGetCurrentPrcb()->MmDemandZeroCount);
+
+ /* Was the fault on an actual user page, or a kernel page for the user? */
+ if (PointerPte <= MiHighestUserPte)
+ {
+ /* User fault, build a user PTE */
+ MI_MAKE_HARDWARE_PTE_USER(&TempPte,
+ PointerPte,
+ PointerPte->u.Soft.Protection,
+ PageFrameIndex);
+ }
+ else
+ {
+ /* Session, kernel, or user PTE, figure it out and build it */
+ MI_MAKE_HARDWARE_PTE(&TempPte,
+ PointerPte,
+ PointerPte->u.Soft.Protection,
+ PageFrameIndex);
+ }
+
+ /* Write the dirty bit for writeable pages */
+ if (TempPte.u.Hard.Write) TempPte.u.Hard.Dirty = TRUE;
+
+ /* And now write down the PTE, making the address valid */
+ MI_WRITE_VALID_PTE(PointerPte, TempPte);
+
+ /* Demand zero */
+ Status = STATUS_PAGE_FAULT_DEMAND_ZERO;
}
else
{
- /* Session, kernel, or user PTE, figure it out and build it */
- MI_MAKE_HARDWARE_PTE(&TempPte,
- PointerPte,
- PointerPte->u.Soft.Protection,
- PageFrameIndex);
- }
-
- /* Write the dirty bit for writeable pages */
- if (TempPte.u.Hard.Write) TempPte.u.Hard.Dirty = TRUE;
-
- /* And now write down the PTE, making the address valid */
- MI_WRITE_VALID_PTE(PointerPte, TempPte);
+ /* The only "prototype PTE" we support is the shared user data path */
+ ASSERT(ProtectionCode == MM_READONLY);
+
+ /* Write the prototype PTE */
+ TempPte = PrototypePte;
+ TempPte.u.Soft.Protection = ProtectionCode;
+ MI_WRITE_INVALID_PTE(PointerPte, TempPte);
+
+ /* Handle the fault */
+ Status = MiDispatchFault(StoreInstruction,
+ Address,
+ PointerPte,
+ ProtoPte,
+ FALSE,
+ CurrentProcess,
+ TrapInformation,
+ Vad);
+ ASSERT(Status == STATUS_PAGE_FAULT_TRANSITION);
+ ASSERT(PointerPte->u.Hard.Valid == 1);
+ ASSERT(PointerPte->u.Hard.PageFrameNumber == MmSharedUserDataPte->u.Hard.PageFrameNumber);
+ }
/* Release the working set */
MiUnlockProcessWorkingSet(CurrentProcess, CurrentThread);
- return STATUS_PAGE_FAULT_DEMAND_ZERO;
+ return Status;
}
/* EOF */