xref: /reactos/ntoskrnl/ke/arm/thrdini.c (revision 299e4305)
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 DECLSPEC_NORETURN
152 VOID
153 KiIdleLoop(VOID)
154 {
155     PKPRCB Prcb = KeGetCurrentPrcb();
156     PKTHREAD OldThread, NewThread;
157 
158     /* Now loop forever */
159     while (TRUE)
160     {
161         /* Start of the idle loop: disable interrupts */
162         _enable();
163         YieldProcessor();
164         YieldProcessor();
165         _disable();
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 interrupts */
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 #ifdef CONFIG_SMP
197             /* Do the swap at SYNCH_LEVEL */
198             KfRaiseIrql(SYNCH_LEVEL);
199 #endif
200 
201             /* Switch away from the idle thread */
202             KiSwapContext(APC_LEVEL, OldThread);
203 
204 #ifdef CONFIG_SMP
205             /* Go back to DISPATCH_LEVEL */
206             KeLowerIrql(DISPATCH_LEVEL);
207 #endif
208         }
209         else
210         {
211             /* Continue staying idle. Note the HAL returns with interrupts on */
212             Prcb->PowerState.IdleFunction(&Prcb->PowerState);
213         }
214     }
215 }
216 
217 BOOLEAN
218 FASTCALL
219 KiSwapContextExit(IN PKTHREAD OldThread,
220                   IN PKSWITCHFRAME SwitchFrame)
221 {
222     PKIPCR Pcr = (PKIPCR)KeGetPcr();
223     PKPROCESS OldProcess, NewProcess;
224     PKTHREAD NewThread;
225     ARM_TTB_REGISTER TtbRegister;
226 
227     /* We are on the new thread stack now */
228     NewThread = Pcr->Prcb.CurrentThread;
229 
230     /* Now we are the new thread. Check if it's in a new process */
231     OldProcess = OldThread->ApcState.Process;
232     NewProcess = NewThread->ApcState.Process;
233     if (OldProcess != NewProcess)
234     {
235         TtbRegister.AsUlong = NewProcess->DirectoryTableBase[0];
236         ASSERT(TtbRegister.Reserved == 0);
237         KeArmTranslationTableRegisterSet(TtbRegister);
238     }
239 
240     /* Increase thread context switches */
241     NewThread->ContextSwitches++;
242 
243     /* DPCs shouldn't be active */
244     if (Pcr->Prcb.DpcRoutineActive)
245     {
246         /* Crash the machine */
247         KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC,
248                      (ULONG_PTR)OldThread,
249                      (ULONG_PTR)NewThread,
250                      (ULONG_PTR)OldThread->InitialStack,
251                      0);
252     }
253 
254     /* Kernel APCs may be pending */
255     if (NewThread->ApcState.KernelApcPending)
256     {
257         /* Are APCs enabled? */
258         if (!NewThread->SpecialApcDisable)
259         {
260             /* Request APC delivery */
261             if (SwitchFrame->ApcBypassDisable) HalRequestSoftwareInterrupt(APC_LEVEL);
262             return TRUE;
263         }
264     }
265 
266     /* Return */
267     return FALSE;
268 }
269 
270 VOID
271 FASTCALL
272 KiSwapContextEntry(IN PKSWITCHFRAME SwitchFrame,
273                    IN ULONG_PTR OldThreadAndApcFlag)
274 {
275     PKIPCR Pcr = (PKIPCR)KeGetPcr();
276     PKTHREAD OldThread, NewThread;
277 
278     /* Save APC bypass disable */
279     SwitchFrame->ApcBypassDisable = OldThreadAndApcFlag & 3;
280 
281     /* Increase context switch count and check if tracing is enabled */
282     Pcr->Prcb.KeContextSwitches++;
283 #if 0
284     if (Pcr->PerfGlobalGroupMask)
285     {
286         /* We don't support this yet on x86 either */
287         DPRINT1("WMI Tracing not supported\n");
288         ASSERT(FALSE);
289     }
290 #endif // 0
291 
292     /* Get thread pointers */
293     OldThread = (PKTHREAD)(OldThreadAndApcFlag & ~3);
294     NewThread = Pcr->Prcb.CurrentThread;
295 
296     /* Get the old thread and set its kernel stack */
297     OldThread->KernelStack = SwitchFrame;
298 
299     /* Do the switch */
300     KiSwitchThreads(OldThread, NewThread->KernelStack);
301 }
302 
303 VOID
304 NTAPI
305 KiDispatchInterrupt(VOID)
306 {
307     PKIPCR Pcr = (PKIPCR)KeGetPcr();
308     PKPRCB Prcb = &Pcr->Prcb;
309     PKTHREAD NewThread, OldThread;
310 
311     /* Disable interrupts */
312     _disable();
313 
314     /* Check for pending timers, pending DPCs, or pending ready threads */
315     if ((Prcb->DpcData[0].DpcQueueDepth) ||
316         (Prcb->TimerRequest) ||
317         (Prcb->DeferredReadyListHead.Next))
318     {
319         /* Retire DPCs while under the DPC stack */
320         //KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack);
321         // FIXME!!! //
322         KiRetireDpcList(Prcb);
323     }
324 
325     /* Re-enable interrupts */
326     _enable();
327 
328     /* Check for quantum end */
329     if (Prcb->QuantumEnd)
330     {
331         /* Handle quantum end */
332         Prcb->QuantumEnd = FALSE;
333         KiQuantumEnd();
334     }
335     else if (Prcb->NextThread)
336     {
337         /* Acquire the PRCB lock */
338         KiAcquirePrcbLock(Prcb);
339 
340         /* Capture current thread data */
341         OldThread = Prcb->CurrentThread;
342         NewThread = Prcb->NextThread;
343 
344         /* Set new thread data */
345         Prcb->NextThread = NULL;
346         Prcb->CurrentThread = NewThread;
347 
348         /* The thread is now running */
349         NewThread->State = Running;
350         OldThread->WaitReason = WrDispatchInt;
351 
352         /* Make the old thread ready */
353         KxQueueReadyThread(OldThread, Prcb);
354 
355         /* Swap to the new thread */
356         KiSwapContext(APC_LEVEL, OldThread);
357     }
358 }
359 
360 /* EOF */
361