[NTOS:PS] On x64 don't fail in NtSetInformationProcess with ProcessUserModeIOPL infor...
[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/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