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
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
17 typedef struct _KSWITCHFRAME
20 BOOLEAN ApcBypassDisable
;
22 } KSWITCHFRAME
, *PKSWITCHFRAME
;
24 typedef struct _KUINIT_FRAME
26 KEXCEPTION_FRAME CtxSwitchFrame
;
27 KEXCEPTION_FRAME ExceptionFrame
;
28 KTRAP_FRAME TrapFrame
;
29 } KUINIT_FRAME
, *PKUINIT_FRAME
;
31 typedef struct _KKINIT_FRAME
33 KEXCEPTION_FRAME CtxSwitchFrame
;
34 } KKINIT_FRAME
, *PKKINIT_FRAME
;
36 /* FUNCTIONS ******************************************************************/
40 KiThreadStartup(VOID
);
45 IN PKTHREAD OldThread
,
50 /* FIXME: THIS IS TOTALLY BUSTED NOW */
53 KiInitializeContextThread(IN PKTHREAD Thread
,
54 IN PKSYSTEM_ROUTINE SystemRoutine
,
55 IN PKSTART_ROUTINE StartRoutine
,
56 IN PVOID StartContext
,
57 IN PCONTEXT ContextPointer
)
59 PKTRAP_FRAME TrapFrame
;
60 PKEXCEPTION_FRAME ExceptionFrame
= NULL
, CtxSwitchFrame
;
63 // Check if this is a user thread
68 // Setup the initial frame
70 PKUINIT_FRAME InitFrame
;
71 InitFrame
= (PKUINIT_FRAME
)((ULONG_PTR
)Thread
->InitialStack
-
72 sizeof(KUINIT_FRAME
));
75 // Setup the Trap Frame and Exception frame
77 TrapFrame
= &InitFrame
->TrapFrame
;
78 ExceptionFrame
= &InitFrame
->ExceptionFrame
;
81 // Zero out the trap frame and exception frame
83 RtlZeroMemory(TrapFrame
, sizeof(KTRAP_FRAME
));
84 RtlZeroMemory(ExceptionFrame
, sizeof(KEXCEPTION_FRAME
));
87 // Set up a trap frame from the context
89 KeContextToTrapFrame(ContextPointer
,
92 ContextPointer
->ContextFlags
| CONTEXT_CONTROL
,
96 // Set the previous mode as user
98 //TrapFrame->PreviousMode = UserMode;
99 Thread
->PreviousMode
= UserMode
;
102 // Clear the return address
104 ExceptionFrame
->Lr
= 0;
107 // Context switch frame to setup below
109 CtxSwitchFrame
= &InitFrame
->CtxSwitchFrame
;
114 // Set up the Initial Frame for the system thread
116 PKKINIT_FRAME InitFrame
;
117 InitFrame
= (PKKINIT_FRAME
)((ULONG_PTR
)Thread
->InitialStack
-
118 sizeof(KKINIT_FRAME
));
121 // Set the previous mode as kernel
123 Thread
->PreviousMode
= KernelMode
;
126 // Context switch frame to setup below
128 CtxSwitchFrame
= &InitFrame
->CtxSwitchFrame
;
132 // Now setup the context switch frame
134 CtxSwitchFrame
->Lr
= (ULONG
)KiThreadStartup
;
135 CtxSwitchFrame
->R11
= (ULONG
)(ExceptionFrame
? ExceptionFrame
: CtxSwitchFrame
);
138 // Set the parameters
140 CtxSwitchFrame
->R4
= (ULONG
)ContextPointer
;
141 CtxSwitchFrame
->R5
= (ULONG
)StartContext
;
142 CtxSwitchFrame
->R6
= (ULONG
)StartRoutine
;
143 CtxSwitchFrame
->R7
= (ULONG
)SystemRoutine
;
146 // Save back the new value of the kernel stack
148 Thread
->KernelStack
= (PVOID
)CtxSwitchFrame
;
155 PKPRCB Prcb
= KeGetCurrentPrcb();
156 PKTHREAD OldThread
, NewThread
;
158 /* Initialize the idle loop: disable interrupts */
164 /* Now loop forever */
167 /* Check for pending timers, pending DPCs, or pending ready threads */
168 if ((Prcb
->DpcData
[0].DpcQueueDepth
) ||
169 (Prcb
->TimerRequest
) ||
170 (Prcb
->DeferredReadyListHead
.Next
))
172 /* Quiesce the DPC software interrupt */
173 HalClearSoftwareInterrupt(DISPATCH_LEVEL
);
176 KiRetireDpcList(Prcb
);
179 /* Check if a new thread is scheduled for execution */
180 if (Prcb
->NextThread
)
182 /* Enable interupts */
185 /* Capture current thread data */
186 OldThread
= Prcb
->CurrentThread
;
187 NewThread
= Prcb
->NextThread
;
189 /* Set new thread data */
190 Prcb
->NextThread
= NULL
;
191 Prcb
->CurrentThread
= NewThread
;
193 /* The thread is now running */
194 NewThread
->State
= Running
;
196 /* Switch away from the idle thread */
197 KiSwapContext(APC_LEVEL
, OldThread
);
199 /* We are back in the idle thread -- disable interrupts again */
207 /* Continue staying idle. Note the HAL returns with interrupts on */
208 Prcb
->PowerState
.IdleFunction(&Prcb
->PowerState
);
215 KiSwapContextExit(IN PKTHREAD OldThread
,
216 IN PKSWITCHFRAME SwitchFrame
)
218 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
219 PKPROCESS OldProcess
, NewProcess
;
221 ARM_TTB_REGISTER TtbRegister
;
223 /* We are on the new thread stack now */
224 NewThread
= Pcr
->PrcbData
.CurrentThread
;
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
)
231 TtbRegister
.AsUlong
= NewProcess
->DirectoryTableBase
[0];
232 ASSERT(TtbRegister
.Reserved
== 0);
233 KeArmTranslationTableRegisterSet(TtbRegister
);
236 /* Increase thread context switches */
237 NewThread
->ContextSwitches
++;
239 /* Load data from switch frame */
240 Pcr
->NtTib
.ExceptionList
= SwitchFrame
->ExceptionList
;
242 /* DPCs shouldn't be active */
243 if (Pcr
->PrcbData
.DpcRoutineActive
)
245 /* Crash the machine */
246 KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC
,
247 (ULONG_PTR
)OldThread
,
248 (ULONG_PTR
)NewThread
,
249 (ULONG_PTR
)OldThread
->InitialStack
,
253 /* Kernel APCs may be pending */
254 if (NewThread
->ApcState
.KernelApcPending
)
256 /* Are APCs enabled? */
257 if (!NewThread
->SpecialApcDisable
)
259 /* Request APC delivery */
260 if (SwitchFrame
->ApcBypassDisable
) HalRequestSoftwareInterrupt(APC_LEVEL
);
271 KiSwapContextEntry(IN PKSWITCHFRAME SwitchFrame
,
272 IN ULONG_PTR OldThreadAndApcFlag
)
274 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
275 PKTHREAD OldThread
, NewThread
;
277 /* Save APC bypass disable */
278 SwitchFrame
->ApcBypassDisable
= OldThreadAndApcFlag
& 3;
279 SwitchFrame
->ExceptionList
= Pcr
->NtTib
.ExceptionList
;
281 /* Increase context switch count and check if tracing is enabled */
282 Pcr
->ContextSwitches
++;
283 if (Pcr
->PerfGlobalGroupMask
)
285 /* We don't support this yet on x86 either */
286 DPRINT1("WMI Tracing not supported\n");
290 /* Get thread pointers */
291 OldThread
= (PKTHREAD
)(OldThreadAndApcFlag
& ~3);
292 NewThread
= Pcr
->PrcbData
.CurrentThread
;
294 /* Get the old thread and set its kernel stack */
295 OldThread
->KernelStack
= SwitchFrame
;
298 KiSwitchThreads(OldThread
, NewThread
->KernelStack
);
303 KiDispatchInterrupt(VOID
)
305 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
306 PKPRCB Prcb
= &Pcr
->PrcbData
;
308 PKTHREAD NewThread
, OldThread
;
310 /* Disable interrupts */
313 /* Check for pending timers, pending DPCs, or pending ready threads */
314 if ((Prcb
->DpcData
[0].DpcQueueDepth
) ||
315 (Prcb
->TimerRequest
) ||
316 (Prcb
->DeferredReadyListHead
.Next
))
318 /* Switch to safe execution context */
319 OldHandler
= Pcr
->NtTib
.ExceptionList
;
320 Pcr
->NtTib
.ExceptionList
= EXCEPTION_CHAIN_END
;
322 /* Retire DPCs while under the DPC stack */
323 //KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack);
325 KiRetireDpcList(Prcb
);
327 /* Restore context */
328 Pcr
->NtTib
.ExceptionList
= OldHandler
;
331 /* Re-enable interrupts */
334 /* Check for quantum end */
335 if (Prcb
->QuantumEnd
)
337 /* Handle quantum end */
338 Prcb
->QuantumEnd
= FALSE
;
341 else if (Prcb
->NextThread
)
343 /* Capture current thread data */
344 OldThread
= Prcb
->CurrentThread
;
345 NewThread
= Prcb
->NextThread
;
347 /* Set new thread data */
348 Prcb
->NextThread
= NULL
;
349 Prcb
->CurrentThread
= NewThread
;
351 /* The thread is now running */
352 NewThread
->State
= Running
;
353 OldThread
->WaitReason
= WrDispatchInt
;
355 /* Make the old thread ready */
356 KxQueueReadyThread(OldThread
, Prcb
);
358 /* Swap to the new thread */
359 KiSwapContext(APC_LEVEL
, OldThread
);