xref: /reactos/ntoskrnl/ke/amd64/thrdini.c (revision c2c66aff)
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 
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->Reserved = 0;
136 }
137 
138 BOOLEAN
139 KiSwapContextResume(
140     IN PKTHREAD NewThread,
141     IN PKTHREAD OldThread,
142     IN BOOLEAN ApcBypass)
143 {
144     PKIPCR Pcr = (PKIPCR)KeGetPcr();
145     PKPROCESS OldProcess, NewProcess;
146 
147     /* Setup ring 0 stack pointer */
148     Pcr->TssBase->Rsp0 = (ULONG64)NewThread->InitialStack; // FIXME: NPX save area?
149     Pcr->Prcb.RspBase = Pcr->TssBase->Rsp0;
150 
151     /* Now we are the new thread. Check if it's in a new process */
152     OldProcess = OldThread->ApcState.Process;
153     NewProcess = NewThread->ApcState.Process;
154     if (OldProcess != NewProcess)
155     {
156         /* Switch address space and flush TLB */
157         __writecr3(NewProcess->DirectoryTableBase[0]);
158 
159         /* Set new TSS fields */
160         //Pcr->TssBase->IoMapBase = NewProcess->IopmOffset;
161     }
162 
163     /* Set TEB pointer and GS base */
164     Pcr->NtTib.Self = (PVOID)NewThread->Teb;
165     if (NewThread->Teb)
166     {
167        /* This will switch the usermode gs */
168        __writemsr(MSR_GS_SWAP, (ULONG64)NewThread->Teb);
169     }
170 
171     /* Increase context switch count */
172     Pcr->ContextSwitches++;
173     NewThread->ContextSwitches++;
174 
175     /* DPCs shouldn't be active */
176     if (Pcr->Prcb.DpcRoutineActive)
177     {
178         /* Crash the machine */
179         KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC,
180                      (ULONG_PTR)OldThread,
181                      (ULONG_PTR)NewThread,
182                      (ULONG_PTR)OldThread->InitialStack,
183                      0);
184     }
185 
186     /* Kernel APCs may be pending */
187     if (NewThread->ApcState.KernelApcPending)
188     {
189         /* Are APCs enabled? */
190         if (!NewThread->SpecialApcDisable)
191         {
192             /* Request APC delivery */
193             if (!ApcBypass)
194                 HalRequestSoftwareInterrupt(APC_LEVEL);
195             else
196                 return TRUE;
197         }
198     }
199 
200     /* Return stating that no kernel APCs are pending*/
201     return FALSE;
202 }
203 
204 /* EOF */
205 
206 
207