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