https://git.reactos.org/?p=reactos.git;a=commitdiff;h=52d1bb5ec978184473b25…
commit 52d1bb5ec978184473b259e1973a7fa33ab9ba69
Author: Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Sat Feb 10 19:52:46 2018 +0100
Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org>
CommitDate: Sat Oct 31 14:23:16 2020 +0100
[NTOS:KE:X64] Simplify KiInitializeUserApc
---
ntoskrnl/ke/amd64/usercall.c | 136 +++++++++++++++++++++----------------------
1 file changed, 65 insertions(+), 71 deletions(-)
diff --git a/ntoskrnl/ke/amd64/usercall.c b/ntoskrnl/ke/amd64/usercall.c
index 61861d521b7..38517cb58fc 100644
--- a/ntoskrnl/ke/amd64/usercall.c
+++ b/ntoskrnl/ke/amd64/usercall.c
@@ -11,32 +11,37 @@
#define NDEBUG
#include <debug.h>
-/*! \name KiInitializeUserApc
-*
-* \brief
-* Prepares the current trap frame (which must have come from user mode)
-* with the ntdll.KiUserApcDispatcher entrypoint, copying a CONTEXT
-* record with the context from the old trap frame to the threads user
-* mode stack.
-*
-* \param ExceptionFrame
-* \param TrapFrame
-* \param NormalRoutine
-* \param NormalContext
-* \param SystemArgument1
-* \param SystemArgument2
-*
-* \remarks
-* This function is called from KiDeliverApc, when the trap frame came
-* from user mode. This happens before a systemcall or interrupt exits back
-* to usermode or when a thread is started from PspUserThreadstartup.
-* The trap exit code will then leave to KiUserApcDispatcher which in turn
-* calls the NormalRoutine, passing NormalContext, SystemArgument1 and
-* SystemArgument2 as parameters. When that function returns, it calls
-* NtContinue to return back to the kernel, where the old context that was
-* saved on the usermode stack is restored and execution is transferred
-* back to usermode, where the original trap originated from.
-*
+/*!
+ * \name KiInitializeUserApc
+ *
+ * \brief
+ * Prepares the current trap frame (which must have come from user mode)
+ * with the ntdll.KiUserApcDispatcher entrypoint, copying a CONTEXT
+ * record with the context from the old trap frame to the threads user
+ * mode stack.
+ *
+ * \param ExceptionFrame - Pointer to the Exception Frame
+ *
+ * \param TrapFrame Pointer to the Trap Frame.
+ *
+ * \param NormalRoutine - Pointer to the NormalRoutine to call.
+ *
+ * \param NormalContext - Pointer to the context to send to the Normal Routine.
+ *
+ * \param SystemArgument[1-2]
+ * Pointer to a set of two parameters that contain untyped data.
+ *
+ * \remarks
+ * This function is called from KiDeliverApc, when the trap frame came
+ * from user mode. This happens before a systemcall or interrupt exits back
+ * to usermode or when a thread is started from PspUserThreadstartup.
+ * The trap exit code will then leave to KiUserApcDispatcher which in turn
+ * calls the NormalRoutine, passing NormalContext, SystemArgument1 and
+ * SystemArgument2 as parameters. When that function returns, it calls
+ * NtContinue to return back to the kernel, where the old context that was
+ * saved on the usermode stack is restored and execution is transferred
+ * back to usermode, where the original trap originated from.
+ *
*--*/
VOID
NTAPI
@@ -48,67 +53,56 @@ KiInitializeUserApc(
_In_ PVOID SystemArgument1,
_In_ PVOID SystemArgument2)
{
- CONTEXT Context;
- ULONG64 AlignedRsp, Stack;
- EXCEPTION_RECORD SehExceptRecord;
+ PCONTEXT Context;
+ EXCEPTION_RECORD ExceptionRecord;
/* Sanity check, that the trap frame is from user mode */
ASSERT((TrapFrame->SegCs & MODE_MASK) != KernelMode);
- /* Convert the current trap frame to a context */
- Context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
- KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
-
- /* We jump to KiUserApcDispatcher in ntdll */
- TrapFrame->Rip = (ULONG64)KeUserApcDispatcher;
-
- /* Setup Ring 3 segments */
- TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK;
- TrapFrame->SegDs = KGDT64_R3_DATA | RPL_MASK;
- TrapFrame->SegEs = KGDT64_R3_DATA | RPL_MASK;
- TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
- TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK;
- TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK;
-
- /* Sanitize EFLAGS, enable interrupts */
- TrapFrame->EFlags = (Context.EFlags & EFLAGS_USER_SANITIZE);
- TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
-
- /* Set parameters for KiUserApcDispatcher */
- Context.P1Home = (ULONG64)NormalContext;
- Context.P2Home = (ULONG64)SystemArgument1;
- Context.P3Home = (ULONG64)SystemArgument2;
- Context.P4Home = (ULONG64)NormalRoutine;
-
- /* Check if thread has IOPL and force it enabled if so */
- //if (KeGetCurrentThread()->Iopl) TrapFrame->EFlags |= EFLAGS_IOPL;
-
- /* Align Stack to 16 bytes and allocate space */
- AlignedRsp = Context.Rsp & ~15;
- Stack = AlignedRsp - sizeof(CONTEXT);
- TrapFrame->Rsp = Stack;
-
- /* The stack must be 16 byte aligned for KiUserApcDispatcher */
- ASSERT((Stack & 15) == 0);
+ /* Align the user tack to 16 bytes and allocate space for a CONTEXT structure */
+ Context = (PCONTEXT)ALIGN_DOWN_POINTER_BY(TrapFrame->Rsp, 16) - 1;
/* Protect with SEH */
_SEH2_TRY
{
- /* Probe the stack */
- ProbeForWrite((PCONTEXT)Stack, sizeof(CONTEXT), 8);
+ /* Probe the context */
+ ProbeForWrite(Context, sizeof(CONTEXT), 16);
+
+ /* Convert the current trap frame to a context */
+ Context->ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS;
+ KeTrapFrameToContext(TrapFrame, ExceptionFrame, Context);
- /* Copy the context */
- RtlCopyMemory((PCONTEXT)Stack, &Context, sizeof(CONTEXT));
+ /* Set parameters for KiUserApcDispatcher */
+ Context->P1Home = (ULONG64)NormalContext;
+ Context->P2Home = (ULONG64)SystemArgument1;
+ Context->P3Home = (ULONG64)SystemArgument2;
+ Context->P4Home = (ULONG64)NormalRoutine;
}
- _SEH2_EXCEPT((RtlCopyMemory(&SehExceptRecord, _SEH2_GetExceptionInformation()->ExceptionRecord, sizeof(EXCEPTION_RECORD)), EXCEPTION_EXECUTE_HANDLER))
+ _SEH2_EXCEPT(ExceptionRecord = *_SEH2_GetExceptionInformation()->ExceptionRecord, EXCEPTION_EXECUTE_HANDLER)
{
/* Dispatch the exception */
- SehExceptRecord.ExceptionAddress = (PVOID)TrapFrame->Rip;
- KiDispatchException(&SehExceptRecord,
+ ExceptionRecord.ExceptionAddress = (PVOID)TrapFrame->Rip;
+ KiDispatchException(&ExceptionRecord,
ExceptionFrame,
TrapFrame,
UserMode,
TRUE);
}
_SEH2_END;
+
+ /* Set the stack pointer to the context record */
+ TrapFrame->Rsp = (ULONG64)Context;
+
+ /* We jump to KiUserApcDispatcher in ntdll */
+ TrapFrame->Rip = (ULONG64)KeUserApcDispatcher;
+
+ /* Setup Ring 3 segments */
+ TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK;
+ TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK;
+ TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK;
+ TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK;
+
+ /* Sanitize EFLAGS, enable interrupts */
+ TrapFrame->EFlags &= EFLAGS_USER_SANITIZE;
+ TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
}
https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c86c55ace74345d8ad917…
commit c86c55ace74345d8ad91763b803579bd034fd6eb
Author: Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Fri Feb 9 20:59:33 2018 +0100
Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org>
CommitDate: Sat Oct 31 14:23:16 2020 +0100
[NTOS:KE:X64] Change the logic of KeSwitchKernelStack and friends to be standards conforming
The previous version (like the x86 one) used a combination of C and asm code, called from C code to switch the stack. This is problematic, since there is no guarantee what assumptions C code makes about the stack (i.e. it can place any kind of stack pointers into registers or on the stack itself.) The new algorithm returns back to the systemcall entry point in asm, which then calls KiConvertToGuiThread, which is also asm and calls KeSwitchKernelStack ...
---
ntoskrnl/ke/amd64/stubs.c | 35 +++++++++++++++++++++++++----------
ntoskrnl/ke/amd64/trap.S | 34 ++++++++++++++++++++++++++++++++--
2 files changed, 57 insertions(+), 12 deletions(-)
diff --git a/ntoskrnl/ke/amd64/stubs.c b/ntoskrnl/ke/amd64/stubs.c
index 9e3624d792f..c23c02b0849 100644
--- a/ntoskrnl/ke/amd64/stubs.c
+++ b/ntoskrnl/ke/amd64/stubs.c
@@ -13,6 +13,10 @@
#define NDEBUG
#include <debug.h>
+ULONG ProcessCount;
+BOOLEAN CcPfEnablePrefetcher;
+SIZE_T KeXStateLength = sizeof(XSAVE_FORMAT);
+
VOID
KiRetireDpcListInDpcStack(
PKPRCB Prcb,
@@ -96,14 +100,28 @@ KiSwitchKernelStackHelper(
LONG_PTR StackOffset,
PVOID OldStackBase);
+/*
+ * Kernel stack layout (example pointers):
+ * 0xFFFFFC0F'2D008000 KTHREAD::StackBase
+ * [XSAVE_AREA size == KeXStateLength = 0x440]
+ * 0xFFFFFC0F'2D007BC0 KTHREAD::StateSaveArea _XSAVE_FORMAT
+ * 0xFFFFFC0F'2D007B90 KTHREAD::InitialStack
+ * [0x190 bytes KTRAP_FRAME]
+ * 0xFFFFFC0F'2D007A00 KTHREAD::TrapFrame
+ * [KSTART_FRAME] or ...
+ * [KSWITCH_FRAME]
+ * 0xFFFFFC0F'2D007230 KTHREAD::KernelStack
+ */
+
PVOID
NTAPI
-KeSwitchKernelStack(PVOID StackBase, PVOID StackLimit)
+KiSwitchKernelStack(PVOID StackBase, PVOID StackLimit)
{
PKTHREAD CurrentThread;
PVOID OldStackBase;
LONG_PTR StackOffset;
SIZE_T StackSize;
+ PKIPCR Pcr;
/* Get the current thread */
CurrentThread = KeGetCurrentThread();
@@ -139,20 +157,17 @@ KeSwitchKernelStack(PVOID StackBase, PVOID StackLimit)
CurrentThread->StackLimit = (ULONG_PTR)StackLimit;
CurrentThread->LargeStack = TRUE;
- /* Adjust the PCR fields */
- __addgsqword(FIELD_OFFSET(KPCR, NtTib.StackBase), StackOffset);
- __addgsqword(FIELD_OFFSET(KIPCR, Prcb.RspBase), StackOffset);
-
- /* Finally switch RSP to the new stack.
- We pass OldStackBase to make sure it is not lost. */
- OldStackBase = KiSwitchKernelStackHelper(StackOffset, OldStackBase);
+ /* Adjust RspBase in the PCR */
+ Pcr = (PKIPCR)KeGetPcr();
+ Pcr->Prcb.RspBase += StackOffset;
- /* Reenable interrupts */
- _enable();
+ /* Adjust Rsp0 in the TSS */
+ Pcr->TssBase->Rsp0 += StackOffset;
return OldStackBase;
}
+
NTSTATUS
NTAPI
KeUserModeCallback(IN ULONG RoutineIndex,
diff --git a/ntoskrnl/ke/amd64/trap.S b/ntoskrnl/ke/amd64/trap.S
index a5ba4998745..d361acb1fb1 100644
--- a/ntoskrnl/ke/amd64/trap.S
+++ b/ntoskrnl/ke/amd64/trap.S
@@ -22,7 +22,6 @@ EXTERN KiDeliverApc:PROC
EXTERN KiDpcInterruptHandler:PROC
EXTERN PsConvertToGuiThread:PROC
EXTERN MmCreateKernelStack:PROC
-EXTERN KeSwitchKernelStack:PROC
EXTERN MmDeleteKernelStack:PROC
#ifdef _WINKD_
@@ -774,7 +773,7 @@ PUBLIC KiSystemCallEntry64
.PROC KiSystemCall64Again
- /* Old stack pointer is in rcx, lie and say we saved it in rbp */
+ /* Old stack pointer is in rcx, lie and say we saved it in rbp */
.setframe rbp, 0
.endprolog
@@ -1023,6 +1022,37 @@ KiSwitchKernelStackHelper:
mov rax, rdx
ret
+EXTERN KiSwitchKernelStack:PROC
+
+PUBLIC KeSwitchKernelStack
+FUNC KeSwitchKernelStack
+
+ sub rsp, 40
+ .allocstack 40
+
+ ; Save rcx
+ mov [rsp], rcx
+ .savereg rcx, 0
+ .endprolog
+
+ ; Call the C handler, which returns the old stack in rax
+ call KiSwitchKernelStack
+
+ ; Restore rcx (StackBase)
+ mov rcx, [rsp]
+
+ ; Switch to new stack: RSP += (StackBase - OldStackBase)
+ sub rcx, rax
+ add rsp, rcx
+
+ ; Deallocate the home frame
+ add rsp, 40
+ ret
+
+ENDFUNC
+
+
+
#ifdef _MSC_VER
#undef lgdt