xref: /reactos/ntoskrnl/ke/amd64/thrdini.c (revision 9393fc32)
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 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         RtlZeroMemory(&InitFrame->ExceptionFrame, sizeof(KEXCEPTION_FRAME));
81 
82         /* Set up a trap frame from the context. */
83         KeContextToTrapFrame(Context,
84                              &InitFrame->ExceptionFrame,
85                              TrapFrame,
86                              CONTEXT_AMD64 | ContextFlags,
87                              UserMode);
88 
89         /* Set SS, DS, ES's RPL Mask properly */
90         TrapFrame->SegSs |= RPL_MASK;
91         TrapFrame->SegDs |= RPL_MASK;
92         TrapFrame->SegEs |= RPL_MASK;
93         TrapFrame->Dr7 = 0;
94 
95         /* Set the previous mode as user */
96         TrapFrame->PreviousMode = UserMode;
97 
98         /* Terminate the Exception Handler List */
99         TrapFrame->ExceptionFrame = 0;
100 
101         /* We return to ... */
102         StartFrame->Return = (ULONG64)KiServiceExit2;
103     }
104     else
105     {
106         PKKINIT_FRAME InitFrame;
107 
108         /* Set up the Initial Frame for the system thread */
109         InitFrame = ((PKKINIT_FRAME)Thread->InitialStack) - 1;
110         StartFrame = &InitFrame->StartFrame;
111         CtxSwitchFrame = &InitFrame->CtxSwitchFrame;
112 
113         /* Save back the new value of the kernel stack. */
114         Thread->KernelStack = (PVOID)InitFrame;
115 
116         /* Tell the thread it will run in Kernel Mode */
117         Thread->PreviousMode = KernelMode;
118 
119         // FIXME Setup the Fx Area
120 
121         /* No NPX State */
122         Thread->NpxState = 0xA;
123 
124         /* We have no return address! */
125         StartFrame->Return = 0;
126     }
127 
128     /* Set up the Context Switch Frame */
129     CtxSwitchFrame->Return = (ULONG64)KiThreadStartup;
130     CtxSwitchFrame->ApcBypass = FALSE;
131 
132     StartFrame->P1Home = (ULONG64)StartRoutine;
133     StartFrame->P2Home = (ULONG64)StartContext;
134     StartFrame->P3Home = 0;
135     StartFrame->P4Home = (ULONG64)SystemRoutine;
136     StartFrame->Reserved = 0;
137 }
138 
139 BOOLEAN
140 KiSwapContextResume(
141     _In_ BOOLEAN ApcBypass,
142     _In_ PKTHREAD OldThread,
143     _In_ PKTHREAD NewThread)
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     /* Old thread os no longer busy */
188     OldThread->SwapBusy = FALSE;
189 
190     /* Kernel APCs may be pending */
191     if (NewThread->ApcState.KernelApcPending)
192     {
193         /* Are APCs enabled? */
194         if ((NewThread->SpecialApcDisable == 0) &&
195             (ApcBypass == 0))
196         {
197             /* Return TRUE to indicate that we want APCs to be delivered */
198             return TRUE;
199         }
200 
201         /* Request an APC interrupt to be delivered later */
202         HalRequestSoftwareInterrupt(APC_LEVEL);
203     }
204 
205     /* Return stating that no kernel APCs are pending*/
206     return FALSE;
207 }
208 
209 /* EOF */
210 
211 
212