4031ac4e6a3afd683b4235e451ce438dff7dd87f
[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->Return = 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->Return = (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->Prcb.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 /* DPCs shouldn't be active */
240 if (Pcr->Prcb.DpcRoutineActive)
241 {
242 /* Crash the machine */
243 KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC,
244 (ULONG_PTR)OldThread,
245 (ULONG_PTR)NewThread,
246 (ULONG_PTR)OldThread->InitialStack,
247 0);
248 }
249
250 /* Kernel APCs may be pending */
251 if (NewThread->ApcState.KernelApcPending)
252 {
253 /* Are APCs enabled? */
254 if (!NewThread->SpecialApcDisable)
255 {
256 /* Request APC delivery */
257 if (SwitchFrame->ApcBypassDisable) HalRequestSoftwareInterrupt(APC_LEVEL);
258 return TRUE;
259 }
260 }
261
262 /* Return */
263 return FALSE;
264 }
265
266 VOID
267 FASTCALL
268 KiSwapContextEntry(IN PKSWITCHFRAME SwitchFrame,
269 IN ULONG_PTR OldThreadAndApcFlag)
270 {
271 PKIPCR Pcr = (PKIPCR)KeGetPcr();
272 PKTHREAD OldThread, NewThread;
273
274 /* Save APC bypass disable */
275 SwitchFrame->ApcBypassDisable = OldThreadAndApcFlag & 3;
276
277 /* Increase context switch count and check if tracing is enabled */
278 Pcr->Prcb.KeContextSwitches++;
279 #if 0
280 if (Pcr->PerfGlobalGroupMask)
281 {
282 /* We don't support this yet on x86 either */
283 DPRINT1("WMI Tracing not supported\n");
284 ASSERT(FALSE);
285 }
286 #endif // 0
287
288 /* Get thread pointers */
289 OldThread = (PKTHREAD)(OldThreadAndApcFlag & ~3);
290 NewThread = Pcr->Prcb.CurrentThread;
291
292 /* Get the old thread and set its kernel stack */
293 OldThread->KernelStack = SwitchFrame;
294
295 /* Do the switch */
296 KiSwitchThreads(OldThread, NewThread->KernelStack);
297 }
298
299 VOID
300 NTAPI
301 KiDispatchInterrupt(VOID)
302 {
303 PKIPCR Pcr = (PKIPCR)KeGetPcr();
304 PKPRCB Prcb = &Pcr->Prcb;
305 PKTHREAD NewThread, OldThread;
306
307 /* Disable interrupts */
308 _disable();
309
310 /* Check for pending timers, pending DPCs, or pending ready threads */
311 if ((Prcb->DpcData[0].DpcQueueDepth) ||
312 (Prcb->TimerRequest) ||
313 (Prcb->DeferredReadyListHead.Next))
314 {
315 /* Retire DPCs while under the DPC stack */
316 //KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack);
317 // FIXME!!! //
318 KiRetireDpcList(Prcb);
319 }
320
321 /* Re-enable interrupts */
322 _enable();
323
324 /* Check for quantum end */
325 if (Prcb->QuantumEnd)
326 {
327 /* Handle quantum end */
328 Prcb->QuantumEnd = FALSE;
329 KiQuantumEnd();
330 }
331 else if (Prcb->NextThread)
332 {
333 /* Capture current thread data */
334 OldThread = Prcb->CurrentThread;
335 NewThread = Prcb->NextThread;
336
337 /* Set new thread data */
338 Prcb->NextThread = NULL;
339 Prcb->CurrentThread = NewThread;
340
341 /* The thread is now running */
342 NewThread->State = Running;
343 OldThread->WaitReason = WrDispatchInt;
344
345 /* Make the old thread ready */
346 KxQueueReadyThread(OldThread, Prcb);
347
348 /* Swap to the new thread */
349 KiSwapContext(APC_LEVEL, OldThread);
350 }
351 }
352
353 /* EOF */