/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
- * FILE: ntoskrnl/ke/i386/thread.c
- * PURPOSE: i386 Thread Context Creation
- * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
+ * FILE: ntoskrnl/ke/amd64/thrdini.c
+ * PURPOSE: amd64 Thread Context Creation
+ * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
+ * Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES ******************************************************************/
#define NDEBUG
#include <debug.h>
+extern void KiInvalidSystemThreadStartupExit(void);
+extern void KiUserThreadStartupExit(void);
+extern void KiServiceExit3(void);
+
typedef struct _KUINIT_FRAME
{
KSWITCH_FRAME CtxSwitchFrame;
KSTART_FRAME StartFrame;
+ KEXCEPTION_FRAME ExceptionFrame;
KTRAP_FRAME TrapFrame;
//FX_SAVE_AREA FxSaveArea;
} KUINIT_FRAME, *PKUINIT_FRAME;
IN PKSYSTEM_ROUTINE SystemRoutine,
IN PKSTART_ROUTINE StartRoutine,
IN PVOID StartContext,
- IN PCONTEXT ContextPointer)
+ IN PCONTEXT Context)
{
//PFX_SAVE_AREA FxSaveArea;
//PFXSAVE_FORMAT FxSaveFormat;
PKSTART_FRAME StartFrame;
PKSWITCH_FRAME CtxSwitchFrame;
PKTRAP_FRAME TrapFrame;
- CONTEXT LocalContext;
- PCONTEXT Context = NULL;
ULONG ContextFlags;
/* Check if this is a With-Context Thread */
- if (ContextPointer)
+ if (Context)
{
- /* Set up the Initial Frame */
PKUINIT_FRAME InitFrame;
- InitFrame = (PKUINIT_FRAME)((ULONG_PTR)Thread->InitialStack -
- sizeof(KUINIT_FRAME));
-
- /* Copy over the context we got */
- RtlCopyMemory(&LocalContext, ContextPointer, sizeof(CONTEXT));
- Context = &LocalContext;
- ContextFlags = CONTEXT_CONTROL;
-
- /* Zero out the trap frame and save area */
- RtlZeroMemory(&InitFrame->TrapFrame,
- KTRAP_FRAME_LENGTH);
-
- /* Setup the Fx Area */
- //FxSaveArea = &InitFrame->FxSaveArea;
-
-// /* Get the FX Save Format Area */
-// FxSaveFormat = (PFXSAVE_FORMAT)Context->ExtendedRegisters;
-//
-// /* Set an initial state */
-// FxSaveFormat->ControlWord = 0x27F;
-// FxSaveFormat->StatusWord = 0;
-// FxSaveFormat->TagWord = 0;
-// FxSaveFormat->ErrorOffset = 0;
-// FxSaveFormat->ErrorSelector = 0;
-// FxSaveFormat->DataOffset = 0;
-// FxSaveFormat->DataSelector = 0;
-// FxSaveFormat->MXCsr = 0x1F80;
-
- /* Set an intial NPX State */
- //Context->FloatSave.Cr0NpxState = 0;
- //FxSaveArea->Cr0NpxState = 0;
- //FxSaveArea->NpxSavedCpu = 0;
-
- /* Now set the context flags depending on XMM support */
- //ContextFlags |= (KeI386FxsrPresent) ? CONTEXT_EXTENDED_REGISTERS :
- // CONTEXT_FLOATING_POINT;
+
+ /* Set up the Initial Frame */
+ InitFrame = ((PKUINIT_FRAME)Thread->InitialStack) - 1;
+ StartFrame = &InitFrame->StartFrame;
+ CtxSwitchFrame = &InitFrame->CtxSwitchFrame;
+
+ /* Save back the new value of the kernel stack. */
+ Thread->KernelStack = (PVOID)InitFrame;
+
+ /* Tell the thread it will run in User Mode */
+ Thread->PreviousMode = UserMode;
+
+ // FIXME Setup the Fx Area
/* Set the Thread's NPX State */
Thread->NpxState = 0xA;
Thread->Header.NpxIrql = PASSIVE_LEVEL;
- /* Disable any debug regiseters */
- Context->ContextFlags &= ~CONTEXT_DEBUG_REGISTERS;
+ /* Make sure, we have control registers, disable debug registers */
+ ASSERT((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL);
+ ContextFlags = Context->ContextFlags & ~CONTEXT_DEBUG_REGISTERS;
/* Setup the Trap Frame */
TrapFrame = &InitFrame->TrapFrame;
+ /* Zero out the trap frame */
+ RtlZeroMemory(TrapFrame, sizeof(KTRAP_FRAME));
+ RtlZeroMemory(&InitFrame->ExceptionFrame, sizeof(KEXCEPTION_FRAME));
+
/* Set up a trap frame from the context. */
KeContextToTrapFrame(Context,
- NULL,
+ &InitFrame->ExceptionFrame,
TrapFrame,
- Context->ContextFlags | ContextFlags,
+ CONTEXT_AMD64 | ContextFlags,
UserMode);
/* Set SS, DS, ES's RPL Mask properly */
/* Terminate the Exception Handler List */
TrapFrame->ExceptionFrame = 0;
- /* Setup the Stack for KiThreadStartup and Context Switching */
- StartFrame = &InitFrame->StartFrame;
- CtxSwitchFrame = &InitFrame->CtxSwitchFrame;
-
- /* Tell the thread it will run in User Mode */
- Thread->PreviousMode = UserMode;
+ /* KiThreadStartup returns to KiUserThreadStartupExit */
+ StartFrame->Return = (ULONG64)KiUserThreadStartupExit;
- /* Tell KiThreadStartup of that too */
-// StartFrame->UserThread = TRUE;
+ /* KiUserThreadStartupExit returns to KiServiceExit3 */
+ InitFrame->ExceptionFrame.Return = (ULONG64)KiServiceExit3;
}
else
{
- /* Set up the Initial Frame for the system thread */
PKKINIT_FRAME InitFrame;
- InitFrame = (PKKINIT_FRAME)((ULONG_PTR)Thread->InitialStack -
- sizeof(KKINIT_FRAME));
- /* Setup the Fx Area */
- //FxSaveArea = &InitFrame->FxSaveArea;
- //RtlZeroMemory(FxSaveArea, sizeof(FX_SAVE_AREA));
+ /* Set up the Initial Frame for the system thread */
+ InitFrame = ((PKKINIT_FRAME)Thread->InitialStack) - 1;
+ StartFrame = &InitFrame->StartFrame;
+ CtxSwitchFrame = &InitFrame->CtxSwitchFrame;
- /* Check if we have Fxsr support */
- DPRINT1("FxsrPresent but did nothing\n");
-// /* Set the stub FX area */
-// FxSaveArea->U.FxArea.ControlWord = 0x27F;
-// FxSaveArea->U.FxArea.MXCsr = 0x1F80;
+ /* Save back the new value of the kernel stack. */
+ Thread->KernelStack = (PVOID)InitFrame;
+
+ /* Tell the thread it will run in Kernel Mode */
+ Thread->PreviousMode = KernelMode;
+
+ // FIXME Setup the Fx Area
/* No NPX State */
Thread->NpxState = 0xA;
- /* Setup the Stack for KiThreadStartup and Context Switching */
- StartFrame = &InitFrame->StartFrame;
- CtxSwitchFrame = &InitFrame->CtxSwitchFrame;
+ /* This must never return! */
+ StartFrame->Return = (ULONG64)KiInvalidSystemThreadStartupExit;
+ }
- /* Tell the thread it will run in Kernel Mode */
- Thread->PreviousMode = KernelMode;
+ /* Set up the Context Switch Frame */
+ CtxSwitchFrame->Return = (ULONG64)KiThreadStartup;
+ CtxSwitchFrame->ApcBypass = TRUE;
+
+ StartFrame->P1Home = (ULONG64)StartRoutine;
+ StartFrame->P2Home = (ULONG64)StartContext;
+ StartFrame->P3Home = 0;
+ StartFrame->P4Home = (ULONG64)SystemRoutine;
+ StartFrame->Reserved = 0;
+}
+
+BOOLEAN
+KiSwapContextResume(
+ _In_ BOOLEAN ApcBypass,
+ _In_ PKTHREAD OldThread,
+ _In_ PKTHREAD NewThread)
+{
+ PKIPCR Pcr = (PKIPCR)KeGetPcr();
+ PKPROCESS OldProcess, NewProcess;
- /* Tell KiThreadStartup of that too */
-// StartFrame->UserThread = FALSE;
+ /* Setup ring 0 stack pointer */
+ Pcr->TssBase->Rsp0 = (ULONG64)NewThread->InitialStack; // FIXME: NPX save area?
+ Pcr->Prcb.RspBase = Pcr->TssBase->Rsp0;
+
+ /* Now we are the new thread. Check if it's in a new process */
+ OldProcess = OldThread->ApcState.Process;
+ NewProcess = NewThread->ApcState.Process;
+ if (OldProcess != NewProcess)
+ {
+ /* Switch address space and flush TLB */
+ __writecr3(NewProcess->DirectoryTableBase[0]);
+
+ /* Set new TSS fields */
+ //Pcr->TssBase->IoMapBase = NewProcess->IopmOffset;
}
- /* Now setup the remaining data for KiThreadStartup */
-// StartFrame->StartContext = StartContext;
-// StartFrame->StartRoutine = StartRoutine;
-// StartFrame->SystemRoutine = SystemRoutine;
+ /* Set TEB pointer and GS base */
+ Pcr->NtTib.Self = (PVOID)NewThread->Teb;
+ if (NewThread->Teb)
+ {
+ /* This will switch the usermode gs */
+ __writemsr(MSR_GS_SWAP, (ULONG64)NewThread->Teb);
+ }
- /* And set up the Context Switch Frame */
-// CtxSwitchFrame->RetAddr = KiThreadStartup;
-// CtxSwitchFrame->ApcBypassDisable = TRUE;
-// CtxSwitchFrame->ExceptionList = EXCEPTION_CHAIN_END;;
+ /* Increase context switch count */
+ Pcr->ContextSwitches++;
+ NewThread->ContextSwitches++;
- /* Save back the new value of the kernel stack. */
- Thread->KernelStack = (PVOID)CtxSwitchFrame;
+ /* DPCs shouldn't be active */
+ if (Pcr->Prcb.DpcRoutineActive)
+ {
+ /* Crash the machine */
+ KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC,
+ (ULONG_PTR)OldThread,
+ (ULONG_PTR)NewThread,
+ (ULONG_PTR)OldThread->InitialStack,
+ 0);
+ }
+
+ /* Old thread os no longer busy */
+ OldThread->SwapBusy = FALSE;
+
+ /* Kernel APCs may be pending */
+ if (NewThread->ApcState.KernelApcPending)
+ {
+ /* Are APCs enabled? */
+ if ((NewThread->SpecialApcDisable == 0) &&
+ (ApcBypass == 0))
+ {
+ /* Return TRUE to indicate that we want APCs to be delivered */
+ return TRUE;
+ }
+
+ /* Request an APC interrupt to be delivered later */
+ HalRequestSoftwareInterrupt(APC_LEVEL);
+ }
+ /* Return stating that no kernel APCs are pending*/
+ return FALSE;
}
/* EOF */