2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/i386/thread.c
5 * PURPOSE: amd64 Thread Context Creation
6 * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
7 * Alex Ionescu (alex@relsoft.net)
10 /* INCLUDES ******************************************************************/
16 typedef struct _KUINIT_FRAME
18 KSWITCH_FRAME CtxSwitchFrame
;
19 KSTART_FRAME StartFrame
;
20 KEXCEPTION_FRAME ExceptionFrame
;
21 KTRAP_FRAME TrapFrame
;
22 //FX_SAVE_AREA FxSaveArea;
23 } KUINIT_FRAME
, *PKUINIT_FRAME
;
25 typedef struct _KKINIT_FRAME
27 KSWITCH_FRAME CtxSwitchFrame
;
28 KSTART_FRAME StartFrame
;
29 //FX_SAVE_AREA FxSaveArea;
30 } KKINIT_FRAME
, *PKKINIT_FRAME
;
32 /* FUNCTIONS *****************************************************************/
36 KiInitializeContextThread(IN PKTHREAD Thread
,
37 IN PKSYSTEM_ROUTINE SystemRoutine
,
38 IN PKSTART_ROUTINE StartRoutine
,
39 IN PVOID StartContext
,
42 //PFX_SAVE_AREA FxSaveArea;
43 //PFXSAVE_FORMAT FxSaveFormat;
44 PKSTART_FRAME StartFrame
;
45 PKSWITCH_FRAME CtxSwitchFrame
;
46 PKTRAP_FRAME TrapFrame
;
49 /* Check if this is a With-Context Thread */
52 PKUINIT_FRAME InitFrame
;
54 /* Set up the Initial Frame */
55 InitFrame
= ((PKUINIT_FRAME
)Thread
->InitialStack
) - 1;
56 StartFrame
= &InitFrame
->StartFrame
;
57 CtxSwitchFrame
= &InitFrame
->CtxSwitchFrame
;
59 /* Save back the new value of the kernel stack. */
60 Thread
->KernelStack
= (PVOID
)InitFrame
;
62 /* Tell the thread it will run in User Mode */
63 Thread
->PreviousMode
= UserMode
;
65 // FIXME Setup the Fx Area
67 /* Set the Thread's NPX State */
68 Thread
->NpxState
= 0xA;
69 Thread
->Header
.NpxIrql
= PASSIVE_LEVEL
;
71 /* Make sure, we have control registers, disable debug registers */
72 ASSERT((Context
->ContextFlags
& CONTEXT_CONTROL
) == CONTEXT_CONTROL
);
73 ContextFlags
= Context
->ContextFlags
& ~CONTEXT_DEBUG_REGISTERS
;
75 /* Setup the Trap Frame */
76 TrapFrame
= &InitFrame
->TrapFrame
;
78 /* Zero out the trap frame */
79 RtlZeroMemory(TrapFrame
, sizeof(KTRAP_FRAME
));
81 /* Set up a trap frame from the context. */
82 KeContextToTrapFrame(Context
,
85 CONTEXT_AMD64
| ContextFlags
,
88 /* Set SS, DS, ES's RPL Mask properly */
89 TrapFrame
->SegSs
|= RPL_MASK
;
90 TrapFrame
->SegDs
|= RPL_MASK
;
91 TrapFrame
->SegEs
|= RPL_MASK
;
94 /* Set the previous mode as user */
95 TrapFrame
->PreviousMode
= UserMode
;
97 /* Terminate the Exception Handler List */
98 TrapFrame
->ExceptionFrame
= 0;
100 /* We return to ... */
101 StartFrame
->Return
= (ULONG64
)KiServiceExit2
;
105 PKKINIT_FRAME InitFrame
;
107 /* Set up the Initial Frame for the system thread */
108 InitFrame
= ((PKKINIT_FRAME
)Thread
->InitialStack
) - 1;
109 StartFrame
= &InitFrame
->StartFrame
;
110 CtxSwitchFrame
= &InitFrame
->CtxSwitchFrame
;
112 /* Save back the new value of the kernel stack. */
113 Thread
->KernelStack
= (PVOID
)InitFrame
;
115 /* Tell the thread it will run in Kernel Mode */
116 Thread
->PreviousMode
= KernelMode
;
118 // FIXME Setup the Fx Area
121 Thread
->NpxState
= 0xA;
123 /* We have no return address! */
124 StartFrame
->Return
= 0;
127 /* Set up the Context Switch Frame */
128 CtxSwitchFrame
->Return
= (ULONG64
)KiThreadStartup
;
129 CtxSwitchFrame
->ApcBypass
= FALSE
;
131 StartFrame
->P1Home
= (ULONG64
)StartRoutine
;
132 StartFrame
->P2Home
= (ULONG64
)StartContext
;
133 StartFrame
->P3Home
= 0;
134 StartFrame
->P4Home
= (ULONG64
)SystemRoutine
;
135 StartFrame
->P5Home
= 0;
141 IN PKTHREAD NewThread
,
142 IN PKTHREAD OldThread
,
143 IN BOOLEAN ApcBypass
)
145 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
146 PKPROCESS OldProcess
, NewProcess
;
148 /* Setup ring 0 stack pointer */
149 Pcr
->TssBase
->Rsp0
= (ULONG64
)NewThread
->InitialStack
; // FIXME: NPX save area?
150 Pcr
->Prcb
.RspBase
= Pcr
->TssBase
->Rsp0
;
152 /* Now we are the new thread. Check if it's in a new process */
153 OldProcess
= OldThread
->ApcState
.Process
;
154 NewProcess
= NewThread
->ApcState
.Process
;
155 if (OldProcess
!= NewProcess
)
157 /* Switch address space and flush TLB */
158 __writecr3(NewProcess
->DirectoryTableBase
[0]);
160 /* Set new TSS fields */
161 //Pcr->TssBase->IoMapBase = NewProcess->IopmOffset;
164 /* Set TEB pointer and GS base */
165 Pcr
->NtTib
.Self
= (PVOID
)NewThread
->Teb
;
168 /* This will switch the usermode gs */
169 __writemsr(MSR_GS_SWAP
, (ULONG64
)NewThread
->Teb
);
172 /* Increase context switch count */
173 Pcr
->ContextSwitches
++;
174 NewThread
->ContextSwitches
++;
176 /* DPCs shouldn't be active */
177 if (Pcr
->Prcb
.DpcRoutineActive
)
179 /* Crash the machine */
180 KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC
,
181 (ULONG_PTR
)OldThread
,
182 (ULONG_PTR
)NewThread
,
183 (ULONG_PTR
)OldThread
->InitialStack
,
187 /* Kernel APCs may be pending */
188 if (NewThread
->ApcState
.KernelApcPending
)
190 /* Are APCs enabled? */
191 if (!NewThread
->SpecialApcDisable
)
193 /* Request APC delivery */
195 HalRequestSoftwareInterrupt(APC_LEVEL
);
201 /* Return stating that no kernel APCs are pending*/