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