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
->Return
= 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
->Return
= (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 interrupts */
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
->Prcb
.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 /* DPCs shouldn't be active */
240 if (Pcr
->Prcb
.DpcRoutineActive
)
242 /* Crash the machine */
243 KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC
,
244 (ULONG_PTR
)OldThread
,
245 (ULONG_PTR
)NewThread
,
246 (ULONG_PTR
)OldThread
->InitialStack
,
250 /* Kernel APCs may be pending */
251 if (NewThread
->ApcState
.KernelApcPending
)
253 /* Are APCs enabled? */
254 if (!NewThread
->SpecialApcDisable
)
256 /* Request APC delivery */
257 if (SwitchFrame
->ApcBypassDisable
) HalRequestSoftwareInterrupt(APC_LEVEL
);
268 KiSwapContextEntry(IN PKSWITCHFRAME SwitchFrame
,
269 IN ULONG_PTR OldThreadAndApcFlag
)
271 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
272 PKTHREAD OldThread
, NewThread
;
274 /* Save APC bypass disable */
275 SwitchFrame
->ApcBypassDisable
= OldThreadAndApcFlag
& 3;
277 /* Increase context switch count and check if tracing is enabled */
278 Pcr
->Prcb
.KeContextSwitches
++;
280 if (Pcr
->PerfGlobalGroupMask
)
282 /* We don't support this yet on x86 either */
283 DPRINT1("WMI Tracing not supported\n");
288 /* Get thread pointers */
289 OldThread
= (PKTHREAD
)(OldThreadAndApcFlag
& ~3);
290 NewThread
= Pcr
->Prcb
.CurrentThread
;
292 /* Get the old thread and set its kernel stack */
293 OldThread
->KernelStack
= SwitchFrame
;
296 KiSwitchThreads(OldThread
, NewThread
->KernelStack
);
301 KiDispatchInterrupt(VOID
)
303 PKIPCR Pcr
= (PKIPCR
)KeGetPcr();
304 PKPRCB Prcb
= &Pcr
->Prcb
;
305 PKTHREAD NewThread
, OldThread
;
307 /* Disable interrupts */
310 /* Check for pending timers, pending DPCs, or pending ready threads */
311 if ((Prcb
->DpcData
[0].DpcQueueDepth
) ||
312 (Prcb
->TimerRequest
) ||
313 (Prcb
->DeferredReadyListHead
.Next
))
315 /* Retire DPCs while under the DPC stack */
316 //KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack);
318 KiRetireDpcList(Prcb
);
321 /* Re-enable interrupts */
324 /* Check for quantum end */
325 if (Prcb
->QuantumEnd
)
327 /* Handle quantum end */
328 Prcb
->QuantumEnd
= FALSE
;
331 else if (Prcb
->NextThread
)
333 /* Capture current thread data */
334 OldThread
= Prcb
->CurrentThread
;
335 NewThread
= Prcb
->NextThread
;
337 /* Set new thread data */
338 Prcb
->NextThread
= NULL
;
339 Prcb
->CurrentThread
= NewThread
;
341 /* The thread is now running */
342 NewThread
->State
= Running
;
343 OldThread
->WaitReason
= WrDispatchInt
;
345 /* Make the old thread ready */
346 KxQueueReadyThread(OldThread
, Prcb
);
348 /* Swap to the new thread */
349 KiSwapContext(APC_LEVEL
, OldThread
);