[NTOS]: Some more ARM build and linker fixes, moving some of the new x86 C code into...
[reactos.git] / reactos / ntoskrnl / ke / arm / thrdini.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/ke/arm/thrdini.c
5 * PURPOSE: Implements thread context setup and startup for ARM machines
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 typedef struct _KSWITCHFRAME
18 {
19 PVOID ExceptionList;
20 BOOLEAN ApcBypassDisable;
21 PVOID RetAddr;
22 } KSWITCHFRAME, *PKSWITCHFRAME;
23
24 typedef struct _KUINIT_FRAME
25 {
26 KEXCEPTION_FRAME CtxSwitchFrame;
27 KEXCEPTION_FRAME ExceptionFrame;
28 KTRAP_FRAME TrapFrame;
29 } KUINIT_FRAME, *PKUINIT_FRAME;
30
31 typedef struct _KKINIT_FRAME
32 {
33 KEXCEPTION_FRAME CtxSwitchFrame;
34 } KKINIT_FRAME, *PKKINIT_FRAME;
35
36 /* FUNCTIONS ******************************************************************/
37
38 VOID
39 NTAPI
40 KiThreadStartup(VOID);
41
42 VOID
43 FASTCALL
44 KiSwitchThreads(
45 IN PKTHREAD OldThread,
46 IN PKTHREAD NewThread
47 );
48
49
50 /* FIXME: THIS IS TOTALLY BUSTED NOW */
51 VOID
52 NTAPI
53 KiInitializeContextThread(IN PKTHREAD Thread,
54 IN PKSYSTEM_ROUTINE SystemRoutine,
55 IN PKSTART_ROUTINE StartRoutine,
56 IN PVOID StartContext,
57 IN PCONTEXT ContextPointer)
58 {
59 PKTRAP_FRAME TrapFrame;
60 PKEXCEPTION_FRAME ExceptionFrame = NULL, CtxSwitchFrame;
61
62 //
63 // Check if this is a user thread
64 //
65 if (ContextPointer)
66 {
67 //
68 // Setup the initial frame
69 //
70 PKUINIT_FRAME InitFrame;
71 InitFrame = (PKUINIT_FRAME)((ULONG_PTR)Thread->InitialStack -
72 sizeof(KUINIT_FRAME));
73
74 //
75 // Setup the Trap Frame and Exception frame
76 //
77 TrapFrame = &InitFrame->TrapFrame;
78 ExceptionFrame = &InitFrame->ExceptionFrame;
79
80 ///
81 // Zero out the trap frame and exception frame
82 //
83 RtlZeroMemory(TrapFrame, sizeof(KTRAP_FRAME));
84 RtlZeroMemory(ExceptionFrame, sizeof(KEXCEPTION_FRAME));
85
86 //
87 // Set up a trap frame from the context
88 //
89 KeContextToTrapFrame(ContextPointer,
90 ExceptionFrame,
91 TrapFrame,
92 ContextPointer->ContextFlags | CONTEXT_CONTROL,
93 UserMode);
94
95 //
96 // Set the previous mode as user
97 //
98 //TrapFrame->PreviousMode = UserMode;
99 Thread->PreviousMode = UserMode;
100
101 //
102 // Clear the return address
103 //
104 ExceptionFrame->Lr = 0;
105
106 //
107 // Context switch frame to setup below
108 //
109 CtxSwitchFrame = &InitFrame->CtxSwitchFrame;
110 }
111 else
112 {
113 //
114 // Set up the Initial Frame for the system thread
115 //
116 PKKINIT_FRAME InitFrame;
117 InitFrame = (PKKINIT_FRAME)((ULONG_PTR)Thread->InitialStack -
118 sizeof(KKINIT_FRAME));
119
120 //
121 // Set the previous mode as kernel
122 //
123 Thread->PreviousMode = KernelMode;
124
125 //
126 // Context switch frame to setup below
127 //
128 CtxSwitchFrame = &InitFrame->CtxSwitchFrame;
129 }
130
131 //
132 // Now setup the context switch frame
133 //
134 CtxSwitchFrame->Lr = (ULONG)KiThreadStartup;
135 CtxSwitchFrame->R11 = (ULONG)(ExceptionFrame ? ExceptionFrame : CtxSwitchFrame);
136
137 //
138 // Set the parameters
139 //
140 CtxSwitchFrame->R4 = (ULONG)ContextPointer;
141 CtxSwitchFrame->R5 = (ULONG)StartContext;
142 CtxSwitchFrame->R6 = (ULONG)StartRoutine;
143 CtxSwitchFrame->R7 = (ULONG)SystemRoutine;
144
145 //
146 // Save back the new value of the kernel stack
147 //
148 Thread->KernelStack = (PVOID)CtxSwitchFrame;
149 }
150
151 VOID
152 FASTCALL
153 KiIdleLoop(VOID)
154 {
155 PKPRCB Prcb = KeGetCurrentPrcb();
156 PKTHREAD OldThread, NewThread;
157
158 /* Initialize the idle loop: disable interrupts */
159 _enable();
160 YieldProcessor();
161 YieldProcessor();
162 _disable();
163
164 /* Now loop forever */
165 while (TRUE)
166 {
167 /* Check for pending timers, pending DPCs, or pending ready threads */
168 if ((Prcb->DpcData[0].DpcQueueDepth) ||
169 (Prcb->TimerRequest) ||
170 (Prcb->DeferredReadyListHead.Next))
171 {
172 /* Quiesce the DPC software interrupt */
173 HalClearSoftwareInterrupt(DISPATCH_LEVEL);
174
175 /* Handle it */
176 KiRetireDpcList(Prcb);
177 }
178
179 /* Check if a new thread is scheduled for execution */
180 if (Prcb->NextThread)
181 {
182 /* Enable interupts */
183 _enable();
184
185 /* Capture current thread data */
186 OldThread = Prcb->CurrentThread;
187 NewThread = Prcb->NextThread;
188
189 /* Set new thread data */
190 Prcb->NextThread = NULL;
191 Prcb->CurrentThread = NewThread;
192
193 /* The thread is now running */
194 NewThread->State = Running;
195
196 /* Switch away from the idle thread */
197 KiSwapContext(APC_LEVEL, OldThread);
198
199 /* We are back in the idle thread -- disable interrupts again */
200 _enable();
201 YieldProcessor();
202 YieldProcessor();
203 _disable();
204 }
205 else
206 {
207 /* Continue staying idle. Note the HAL returns with interrupts on */
208 Prcb->PowerState.IdleFunction(&Prcb->PowerState);
209 }
210 }
211 }
212
213 BOOLEAN
214 FASTCALL
215 KiSwapContextExit(IN PKTHREAD OldThread,
216 IN PKSWITCHFRAME SwitchFrame)
217 {
218 PKIPCR Pcr = (PKIPCR)KeGetPcr();
219 PKPROCESS OldProcess, NewProcess;
220 PKTHREAD NewThread;
221 ARM_TTB_REGISTER TtbRegister;
222
223 /* We are on the new thread stack now */
224 NewThread = Pcr->PrcbData.CurrentThread;
225
226 /* Now we are the new thread. Check if it's in a new process */
227 OldProcess = OldThread->ApcState.Process;
228 NewProcess = NewThread->ApcState.Process;
229 if (OldProcess != NewProcess)
230 {
231 TtbRegister.AsUlong = NewProcess->DirectoryTableBase[0];
232 ASSERT(TtbRegister.Reserved == 0);
233 KeArmTranslationTableRegisterSet(TtbRegister);
234 }
235
236 /* Increase thread context switches */
237 NewThread->ContextSwitches++;
238
239 /* Load data from switch frame */
240 Pcr->NtTib.ExceptionList = SwitchFrame->ExceptionList;
241
242 /* DPCs shouldn't be active */
243 if (Pcr->PrcbData.DpcRoutineActive)
244 {
245 /* Crash the machine */
246 KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC,
247 (ULONG_PTR)OldThread,
248 (ULONG_PTR)NewThread,
249 (ULONG_PTR)OldThread->InitialStack,
250 0);
251 }
252
253 /* Kernel APCs may be pending */
254 if (NewThread->ApcState.KernelApcPending)
255 {
256 /* Are APCs enabled? */
257 if (!NewThread->SpecialApcDisable)
258 {
259 /* Request APC delivery */
260 if (SwitchFrame->ApcBypassDisable) HalRequestSoftwareInterrupt(APC_LEVEL);
261 return TRUE;
262 }
263 }
264
265 /* Return */
266 return FALSE;
267 }
268
269 VOID
270 FASTCALL
271 KiSwapContextEntry(IN PKSWITCHFRAME SwitchFrame,
272 IN ULONG_PTR OldThreadAndApcFlag)
273 {
274 PKIPCR Pcr = (PKIPCR)KeGetPcr();
275 PKTHREAD OldThread, NewThread;
276
277 /* Save APC bypass disable */
278 SwitchFrame->ApcBypassDisable = OldThreadAndApcFlag & 3;
279 SwitchFrame->ExceptionList = Pcr->NtTib.ExceptionList;
280
281 /* Increase context switch count and check if tracing is enabled */
282 Pcr->ContextSwitches++;
283 if (Pcr->PerfGlobalGroupMask)
284 {
285 /* We don't support this yet on x86 either */
286 DPRINT1("WMI Tracing not supported\n");
287 ASSERT(FALSE);
288 }
289
290 /* Get thread pointers */
291 OldThread = (PKTHREAD)(OldThreadAndApcFlag & ~3);
292 NewThread = Pcr->PrcbData.CurrentThread;
293
294 /* Get the old thread and set its kernel stack */
295 OldThread->KernelStack = SwitchFrame;
296
297 /* Do the switch */
298 KiSwitchThreads(OldThread, NewThread->KernelStack);
299 }
300
301 VOID
302 NTAPI
303 KiDispatchInterrupt(VOID)
304 {
305 PKIPCR Pcr = (PKIPCR)KeGetPcr();
306 PKPRCB Prcb = &Pcr->PrcbData;
307 PVOID OldHandler;
308 PKTHREAD NewThread, OldThread;
309
310 /* Disable interrupts */
311 _disable();
312
313 /* Check for pending timers, pending DPCs, or pending ready threads */
314 if ((Prcb->DpcData[0].DpcQueueDepth) ||
315 (Prcb->TimerRequest) ||
316 (Prcb->DeferredReadyListHead.Next))
317 {
318 /* Switch to safe execution context */
319 OldHandler = Pcr->NtTib.ExceptionList;
320 Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
321
322 /* Retire DPCs while under the DPC stack */
323 //KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack);
324 // FIXME!!! //
325 KiRetireDpcList(Prcb);
326
327 /* Restore context */
328 Pcr->NtTib.ExceptionList = OldHandler;
329 }
330
331 /* Re-enable interrupts */
332 _enable();
333
334 /* Check for quantum end */
335 if (Prcb->QuantumEnd)
336 {
337 /* Handle quantum end */
338 Prcb->QuantumEnd = FALSE;
339 KiQuantumEnd();
340 }
341 else if (Prcb->NextThread)
342 {
343 /* Capture current thread data */
344 OldThread = Prcb->CurrentThread;
345 NewThread = Prcb->NextThread;
346
347 /* Set new thread data */
348 Prcb->NextThread = NULL;
349 Prcb->CurrentThread = NewThread;
350
351 /* The thread is now running */
352 NewThread->State = Running;
353 OldThread->WaitReason = WrDispatchInt;
354
355 /* Make the old thread ready */
356 KxQueueReadyThread(OldThread, Prcb);
357
358 /* Swap to the new thread */
359 KiSwapContext(APC_LEVEL, OldThread);
360 }
361 }
362
363 /* EOF */