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