2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/amd64/thrdini.c
5 * PURPOSE: amd64 Thread Context Creation
6 * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
7 * Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES ******************************************************************/
16 extern void KiInvalidSystemThreadStartupExit(void);
17 extern void KiUserThreadStartupExit(void);
18 extern void KiServiceExit3(void);
20 typedef struct _KUINIT_FRAME
22 KSWITCH_FRAME CtxSwitchFrame
;
23 KSTART_FRAME StartFrame
;
24 KEXCEPTION_FRAME ExceptionFrame
;
25 KTRAP_FRAME TrapFrame
;
26 //FX_SAVE_AREA FxSaveArea;
27 } KUINIT_FRAME
, *PKUINIT_FRAME
;
29 typedef struct _KKINIT_FRAME
31 KSWITCH_FRAME CtxSwitchFrame
;
32 KSTART_FRAME StartFrame
;
33 //FX_SAVE_AREA FxSaveArea;
34 } KKINIT_FRAME
, *PKKINIT_FRAME
;
36 /* FUNCTIONS *****************************************************************/
40 KiInitializeContextThread(IN PKTHREAD Thread
,
41 IN PKSYSTEM_ROUTINE SystemRoutine
,
42 IN PKSTART_ROUTINE StartRoutine
,
43 IN PVOID StartContext
,
46 //PFX_SAVE_AREA FxSaveArea;
47 //PFXSAVE_FORMAT FxSaveFormat;
48 PKSTART_FRAME StartFrame
;
49 PKSWITCH_FRAME CtxSwitchFrame
;
50 PKTRAP_FRAME TrapFrame
;
53 /* Check if this is a With-Context Thread */
56 PKUINIT_FRAME InitFrame
;
58 /* Set up the Initial Frame */
59 InitFrame
= ((PKUINIT_FRAME
)Thread
->InitialStack
) - 1;
60 StartFrame
= &InitFrame
->StartFrame
;
61 CtxSwitchFrame
= &InitFrame
->CtxSwitchFrame
;
63 /* Save back the new value of the kernel stack. */
64 Thread
->KernelStack
= (PVOID
)InitFrame
;
66 /* Tell the thread it will run in User Mode */
67 Thread
->PreviousMode
= UserMode
;
69 // FIXME Setup the Fx Area
71 /* Set the Thread's NPX State */
72 Thread
->NpxState
= 0xA;
73 Thread
->Header
.NpxIrql
= PASSIVE_LEVEL
;
75 /* Make sure, we have control registers, disable debug registers */
76 ASSERT((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
);
77 ContextFlags
= Context
->ContextFlags
& ~CONTEXT_DEBUG_REGISTERS
;
79 /* Setup the Trap Frame */
80 TrapFrame
= &InitFrame
->TrapFrame
;
82 /* Zero out the trap frame */
83 RtlZeroMemory(TrapFrame
, sizeof(KTRAP_FRAME
));
84 RtlZeroMemory(&InitFrame
->ExceptionFrame
, sizeof(KEXCEPTION_FRAME
));
86 /* Set up a trap frame from the context. */
87 KeContextToTrapFrame(Context
,
88 &InitFrame
->ExceptionFrame
,
90 CONTEXT_AMD64
| ContextFlags
,
93 /* Set SS, DS, ES's RPL Mask properly */
94 TrapFrame
->SegSs
|= RPL_MASK
;
95 TrapFrame
->SegDs
|= RPL_MASK
;
96 TrapFrame
->SegEs
|= RPL_MASK
;
99 /* Set the previous mode as user */
100 TrapFrame
->PreviousMode
= UserMode
;
102 /* Terminate the Exception Handler List */
103 TrapFrame
->ExceptionFrame
= 0;
105 /* KiThreadStartup returns to KiUserThreadStartupExit */
106 StartFrame
->Return
= (ULONG64
)KiUserThreadStartupExit
;
108 /* KiUserThreadStartupExit returns to KiServiceExit3 */
109 InitFrame
->ExceptionFrame
.Return
= (ULONG64
)KiServiceExit3
;
113 PKKINIT_FRAME InitFrame
;
115 /* Set up the Initial Frame for the system thread */
116 InitFrame
= ((PKKINIT_FRAME
)Thread
->InitialStack
) - 1;
117 StartFrame
= &InitFrame
->StartFrame
;
118 CtxSwitchFrame
= &InitFrame
->CtxSwitchFrame
;
120 /* Save back the new value of the kernel stack. */
121 Thread
->KernelStack
= (PVOID
)InitFrame
;
123 /* Tell the thread it will run in Kernel Mode */
124 Thread
->PreviousMode
= KernelMode
;
126 // FIXME Setup the Fx Area
129 Thread
->NpxState
= 0xA;
131 /* This must never return! */
132 StartFrame
->Return
= (ULONG64
)KiInvalidSystemThreadStartupExit
;
135 /* Set up the Context Switch Frame */
136 CtxSwitchFrame
->Return
= (ULONG64
)KiThreadStartup
;
137 CtxSwitchFrame
->ApcBypass
= TRUE
;
139 StartFrame
->P1Home
= (ULONG64
)StartRoutine
;
140 StartFrame
->P2Home
= (ULONG64
)StartContext
;
141 StartFrame
->P3Home
= 0;
142 StartFrame
->P4Home
= (ULONG64
)SystemRoutine
;
143 StartFrame
->Reserved
= 0;
148 _In_ BOOLEAN ApcBypass
,
149 _In_ PKTHREAD OldThread
,
150 _In_ PKTHREAD NewThread
)
152 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
153 PKPROCESS OldProcess
, NewProcess
;
155 /* Setup ring 0 stack pointer */
156 Pcr
->TssBase
->Rsp0
= (ULONG64
)NewThread
->InitialStack
; // FIXME: NPX save area?
157 Pcr
->Prcb
.RspBase
= Pcr
->TssBase
->Rsp0
;
159 /* Now we are the new thread. Check if it's in a new process */
160 OldProcess
= OldThread
->ApcState
.Process
;
161 NewProcess
= NewThread
->ApcState
.Process
;
162 if (OldProcess
!= NewProcess
)
164 /* Switch address space and flush TLB */
165 __writecr3(NewProcess
->DirectoryTableBase
[0]);
167 /* Set new TSS fields */
168 //Pcr->TssBase->IoMapBase = NewProcess->IopmOffset;
171 /* Set TEB pointer and GS base */
172 Pcr
->NtTib
.Self
= (PVOID
)NewThread
->Teb
;
175 /* This will switch the usermode gs */
176 __writemsr(MSR_GS_SWAP
, (ULONG64
)NewThread
->Teb
);
179 /* Increase context switch count */
180 Pcr
->ContextSwitches
++;
181 NewThread
->ContextSwitches
++;
183 /* DPCs shouldn't be active */
184 if (Pcr
->Prcb
.DpcRoutineActive
)
186 /* Crash the machine */
187 KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC
,
188 (ULONG_PTR
)OldThread
,
189 (ULONG_PTR
)NewThread
,
190 (ULONG_PTR
)OldThread
->InitialStack
,
194 /* Old thread os no longer busy */
195 OldThread
->SwapBusy
= FALSE
;
197 /* Kernel APCs may be pending */
198 if (NewThread
->ApcState
.KernelApcPending
)
200 /* Are APCs enabled? */
201 if ((NewThread
->SpecialApcDisable
== 0) &&
204 /* Return TRUE to indicate that we want APCs to be delivered */
208 /* Request an APC interrupt to be delivered later */
209 HalRequestSoftwareInterrupt(APC_LEVEL
);
212 /* Return stating that no kernel APCs are pending*/