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