Create this branch to work on loading of different Kernel-Debugger DLL providers...
[reactos.git] / ntoskrnl / ke / amd64 / thrdini.c
1 /*
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)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 typedef struct _KUINIT_FRAME
17 {
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;
24
25 typedef struct _KKINIT_FRAME
26 {
27 KSWITCH_FRAME CtxSwitchFrame;
28 KSTART_FRAME StartFrame;
29 //FX_SAVE_AREA FxSaveArea;
30 } KKINIT_FRAME, *PKKINIT_FRAME;
31
32 /* FUNCTIONS *****************************************************************/
33
34 VOID
35 NTAPI
36 KiInitializeContextThread(IN PKTHREAD Thread,
37 IN PKSYSTEM_ROUTINE SystemRoutine,
38 IN PKSTART_ROUTINE StartRoutine,
39 IN PVOID StartContext,
40 IN PCONTEXT Context)
41 {
42 //PFX_SAVE_AREA FxSaveArea;
43 //PFXSAVE_FORMAT FxSaveFormat;
44 PKSTART_FRAME StartFrame;
45 PKSWITCH_FRAME CtxSwitchFrame;
46 PKTRAP_FRAME TrapFrame;
47 ULONG ContextFlags;
48
49 /* Check if this is a With-Context Thread */
50 if (Context)
51 {
52 PKUINIT_FRAME InitFrame;
53
54 /* Set up the Initial Frame */
55 InitFrame = ((PKUINIT_FRAME)Thread->InitialStack) - 1;
56 StartFrame = &InitFrame->StartFrame;
57 CtxSwitchFrame = &InitFrame->CtxSwitchFrame;
58
59 /* Save back the new value of the kernel stack. */
60 Thread->KernelStack = (PVOID)InitFrame;
61
62 /* Tell the thread it will run in User Mode */
63 Thread->PreviousMode = UserMode;
64
65 // FIXME Setup the Fx Area
66
67 /* Set the Thread's NPX State */
68 Thread->NpxState = 0xA;
69 Thread->Header.NpxIrql = PASSIVE_LEVEL;
70
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;
74
75 /* Setup the Trap Frame */
76 TrapFrame = &InitFrame->TrapFrame;
77
78 /* Zero out the trap frame */
79 RtlZeroMemory(TrapFrame, sizeof(KTRAP_FRAME));
80
81 /* Set up a trap frame from the context. */
82 KeContextToTrapFrame(Context,
83 NULL,
84 TrapFrame,
85 CONTEXT_AMD64 | ContextFlags,
86 UserMode);
87
88 /* Set SS, DS, ES's RPL Mask properly */
89 TrapFrame->SegSs |= RPL_MASK;
90 TrapFrame->SegDs |= RPL_MASK;
91 TrapFrame->SegEs |= RPL_MASK;
92 TrapFrame->Dr7 = 0;
93
94 /* Set the previous mode as user */
95 TrapFrame->PreviousMode = UserMode;
96
97 /* Terminate the Exception Handler List */
98 TrapFrame->ExceptionFrame = 0;
99
100 /* We return to ... */
101 StartFrame->Return = (ULONG64)KiServiceExit2;
102 }
103 else
104 {
105 PKKINIT_FRAME InitFrame;
106
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;
111
112 /* Save back the new value of the kernel stack. */
113 Thread->KernelStack = (PVOID)InitFrame;
114
115 /* Tell the thread it will run in Kernel Mode */
116 Thread->PreviousMode = KernelMode;
117
118 // FIXME Setup the Fx Area
119
120 /* No NPX State */
121 Thread->NpxState = 0xA;
122
123 /* We have no return address! */
124 StartFrame->Return = 0;
125 }
126
127 /* Set up the Context Switch Frame */
128 CtxSwitchFrame->Return = (ULONG64)KiThreadStartup;
129 CtxSwitchFrame->ApcBypass = FALSE;
130
131 StartFrame->P1Home = (ULONG64)StartRoutine;
132 StartFrame->P2Home = (ULONG64)StartContext;
133 StartFrame->P3Home = 0;
134 StartFrame->P4Home = (ULONG64)SystemRoutine;
135 StartFrame->P5Home = 0;
136
137 }
138
139 BOOLEAN
140 KiSwapContextResume(
141 IN PKTHREAD NewThread,
142 IN PKTHREAD OldThread,
143 IN BOOLEAN ApcBypass)
144 {
145 PKIPCR Pcr = (PKIPCR)KeGetPcr();
146 PKPROCESS OldProcess, NewProcess;
147
148 /* Setup ring 0 stack pointer */
149 Pcr->TssBase->Rsp0 = (ULONG64)NewThread->InitialStack; // FIXME: NPX save area?
150 Pcr->Prcb.RspBase = Pcr->TssBase->Rsp0;
151
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)
156 {
157 /* Switch address space and flush TLB */
158 __writecr3(NewProcess->DirectoryTableBase[0]);
159
160 /* Set new TSS fields */
161 //Pcr->TssBase->IoMapBase = NewProcess->IopmOffset;
162 }
163
164 /* Set TEB pointer and GS base */
165 Pcr->NtTib.Self = (PVOID)NewThread->Teb;
166 if (NewThread->Teb)
167 {
168 /* This will switch the usermode gs */
169 __writemsr(MSR_GS_SWAP, (ULONG64)NewThread->Teb);
170 }
171
172 /* Increase context switch count */
173 Pcr->ContextSwitches++;
174 NewThread->ContextSwitches++;
175
176 /* DPCs shouldn't be active */
177 if (Pcr->Prcb.DpcRoutineActive)
178 {
179 /* Crash the machine */
180 KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC,
181 (ULONG_PTR)OldThread,
182 (ULONG_PTR)NewThread,
183 (ULONG_PTR)OldThread->InitialStack,
184 0);
185 }
186
187 /* Kernel APCs may be pending */
188 if (NewThread->ApcState.KernelApcPending)
189 {
190 /* Are APCs enabled? */
191 if (!NewThread->SpecialApcDisable)
192 {
193 /* Request APC delivery */
194 if (!ApcBypass)
195 HalRequestSoftwareInterrupt(APC_LEVEL);
196 else
197 return TRUE;
198 }
199 }
200
201 /* Return stating that no kernel APCs are pending*/
202 return FALSE;
203 }
204
205 /* EOF */
206
207