Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenthrdini.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS kernel 00004 * FILE: ntoskrnl/ke/i386/thread.c 00005 * PURPOSE: i386 Thread Context Creation 00006 * PROGRAMMER: Alex Ionescu (alex@relsoft.net) 00007 */ 00008 00009 /* INCLUDES ******************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 typedef struct _KSWITCHFRAME 00016 { 00017 PVOID ExceptionList; 00018 BOOLEAN ApcBypassDisable; 00019 PVOID RetAddr; 00020 } KSWITCHFRAME, *PKSWITCHFRAME; 00021 00022 typedef struct _KSTART_FRAME 00023 { 00024 PKSYSTEM_ROUTINE SystemRoutine; 00025 PKSTART_ROUTINE StartRoutine; 00026 PVOID StartContext; 00027 BOOLEAN UserThread; 00028 } KSTART_FRAME, *PKSTART_FRAME; 00029 00030 typedef struct _KUINIT_FRAME 00031 { 00032 KSWITCHFRAME CtxSwitchFrame; 00033 KSTART_FRAME StartFrame; 00034 KTRAP_FRAME TrapFrame; 00035 FX_SAVE_AREA FxSaveArea; 00036 } KUINIT_FRAME, *PKUINIT_FRAME; 00037 00038 typedef struct _KKINIT_FRAME 00039 { 00040 KSWITCHFRAME CtxSwitchFrame; 00041 KSTART_FRAME StartFrame; 00042 FX_SAVE_AREA FxSaveArea; 00043 } KKINIT_FRAME, *PKKINIT_FRAME; 00044 00045 VOID 00046 FASTCALL 00047 KiSwitchThreads( 00048 IN PKTHREAD OldThread, 00049 IN PKTHREAD NewThread 00050 ); 00051 00052 VOID 00053 FASTCALL 00054 KiRetireDpcListInDpcStack( 00055 IN PKPRCB Prcb, 00056 IN PVOID DpcStack 00057 ); 00058 00059 /* FUNCTIONS *****************************************************************/ 00060 00061 VOID 00062 NTAPI 00063 KiThreadStartup(VOID) 00064 { 00065 PKTRAP_FRAME TrapFrame; 00066 PKSTART_FRAME StartFrame; 00067 PKUINIT_FRAME InitFrame; 00068 00069 /* Get the start and trap frames */ 00070 InitFrame = KeGetCurrentThread()->KernelStack; 00071 StartFrame = &InitFrame->StartFrame; 00072 TrapFrame = &InitFrame->TrapFrame; 00073 00074 /* Lower to APC level */ 00075 KfLowerIrql(APC_LEVEL); 00076 00077 /* Call the system routine */ 00078 StartFrame->SystemRoutine(StartFrame->StartRoutine, StartFrame->StartContext); 00079 00080 /* If we returned, we better be a user thread */ 00081 if (!StartFrame->UserThread) DbgBreakPoint(); 00082 00083 /* Exit to user-mode */ 00084 KiServiceExit2(TrapFrame); 00085 } 00086 00087 VOID 00088 NTAPI 00089 KiInitializeContextThread(IN PKTHREAD Thread, 00090 IN PKSYSTEM_ROUTINE SystemRoutine, 00091 IN PKSTART_ROUTINE StartRoutine, 00092 IN PVOID StartContext, 00093 IN PCONTEXT ContextPointer) 00094 { 00095 PFX_SAVE_AREA FxSaveArea; 00096 PFXSAVE_FORMAT FxSaveFormat; 00097 PKSTART_FRAME StartFrame; 00098 PKSWITCHFRAME CtxSwitchFrame; 00099 PKTRAP_FRAME TrapFrame; 00100 CONTEXT LocalContext; 00101 PCONTEXT Context = NULL; 00102 ULONG ContextFlags; 00103 00104 /* Check if this is a With-Context Thread */ 00105 if (ContextPointer) 00106 { 00107 /* Set up the Initial Frame */ 00108 PKUINIT_FRAME InitFrame; 00109 InitFrame = (PKUINIT_FRAME)((ULONG_PTR)Thread->InitialStack - 00110 sizeof(KUINIT_FRAME)); 00111 00112 /* Copy over the context we got */ 00113 RtlCopyMemory(&LocalContext, ContextPointer, sizeof(CONTEXT)); 00114 Context = &LocalContext; 00115 ContextFlags = CONTEXT_CONTROL; 00116 00117 /* Zero out the trap frame and save area */ 00118 RtlZeroMemory(&InitFrame->TrapFrame, 00119 KTRAP_FRAME_LENGTH + sizeof(FX_SAVE_AREA)); 00120 00121 /* Setup the Fx Area */ 00122 FxSaveArea = &InitFrame->FxSaveArea; 00123 00124 /* Check if we support FXsr */ 00125 if (KeI386FxsrPresent) 00126 { 00127 /* Get the FX Save Format Area */ 00128 FxSaveFormat = (PFXSAVE_FORMAT)Context->ExtendedRegisters; 00129 00130 /* Set an initial state */ 00131 FxSaveFormat->ControlWord = 0x27F; 00132 FxSaveFormat->StatusWord = 0; 00133 FxSaveFormat->TagWord = 0; 00134 FxSaveFormat->ErrorOffset = 0; 00135 FxSaveFormat->ErrorSelector = 0; 00136 FxSaveFormat->DataOffset = 0; 00137 FxSaveFormat->DataSelector = 0; 00138 FxSaveFormat->MXCsr = 0x1F80; 00139 } 00140 else 00141 { 00142 /* Setup the regular save area */ 00143 Context->FloatSave.ControlWord = 0x27F; 00144 Context->FloatSave.StatusWord = 0; 00145 Context->FloatSave.TagWord = -1; 00146 Context->FloatSave.ErrorOffset = 0; 00147 Context->FloatSave.ErrorSelector = 0; 00148 Context->FloatSave.DataOffset =0; 00149 Context->FloatSave.DataSelector = 0; 00150 } 00151 00152 /* Check if the CPU has NPX */ 00153 if (KeI386NpxPresent) 00154 { 00155 /* Set an intial NPX State */ 00156 Context->FloatSave.Cr0NpxState = 0; 00157 FxSaveArea->Cr0NpxState = 0; 00158 FxSaveArea->NpxSavedCpu = 0; 00159 00160 /* Now set the context flags depending on XMM support */ 00161 ContextFlags |= (KeI386FxsrPresent) ? CONTEXT_EXTENDED_REGISTERS : 00162 CONTEXT_FLOATING_POINT; 00163 00164 /* Set the Thread's NPX State */ 00165 Thread->NpxState = NPX_STATE_NOT_LOADED; 00166 Thread->Header.NpxIrql = PASSIVE_LEVEL; 00167 } 00168 else 00169 { 00170 /* We'll use emulation */ 00171 FxSaveArea->Cr0NpxState = CR0_EM; 00172 Thread->NpxState = NPX_STATE_NOT_LOADED &~ CR0_MP; 00173 } 00174 00175 /* Disable any debug registers */ 00176 Context->ContextFlags &= ~CONTEXT_DEBUG_REGISTERS; 00177 00178 /* Setup the Trap Frame */ 00179 TrapFrame = &InitFrame->TrapFrame; 00180 00181 /* Set up a trap frame from the context. */ 00182 KeContextToTrapFrame(Context, 00183 NULL, 00184 TrapFrame, 00185 Context->ContextFlags | ContextFlags, 00186 UserMode); 00187 00188 /* Set SS, DS, ES's RPL Mask properly */ 00189 TrapFrame->HardwareSegSs |= RPL_MASK; 00190 TrapFrame->SegDs |= RPL_MASK; 00191 TrapFrame->SegEs |= RPL_MASK; 00192 TrapFrame->Dr7 = 0; 00193 00194 /* Set the debug mark */ 00195 TrapFrame->DbgArgMark = 0xBADB0D00; 00196 00197 /* Set the previous mode as user */ 00198 TrapFrame->PreviousPreviousMode = UserMode; 00199 00200 /* Terminate the Exception Handler List */ 00201 TrapFrame->ExceptionList = EXCEPTION_CHAIN_END; 00202 00203 /* Setup the Stack for KiThreadStartup and Context Switching */ 00204 StartFrame = &InitFrame->StartFrame; 00205 CtxSwitchFrame = &InitFrame->CtxSwitchFrame; 00206 00207 /* Tell the thread it will run in User Mode */ 00208 Thread->PreviousMode = UserMode; 00209 00210 /* Tell KiThreadStartup of that too */ 00211 StartFrame->UserThread = TRUE; 00212 } 00213 else 00214 { 00215 /* Set up the Initial Frame for the system thread */ 00216 PKKINIT_FRAME InitFrame; 00217 InitFrame = (PKKINIT_FRAME)((ULONG_PTR)Thread->InitialStack - 00218 sizeof(KKINIT_FRAME)); 00219 00220 /* Setup the Fx Area */ 00221 FxSaveArea = &InitFrame->FxSaveArea; 00222 RtlZeroMemory(FxSaveArea, sizeof(FX_SAVE_AREA)); 00223 00224 /* Check if we have Fxsr support */ 00225 if (KeI386FxsrPresent) 00226 { 00227 /* Set the stub FX area */ 00228 FxSaveArea->U.FxArea.ControlWord = 0x27F; 00229 FxSaveArea->U.FxArea.MXCsr = 0x1F80; 00230 } 00231 else 00232 { 00233 /* Set the stub FN area */ 00234 FxSaveArea->U.FnArea.ControlWord = 0x27F; 00235 FxSaveArea->U.FnArea.TagWord = -1; 00236 } 00237 00238 /* No NPX State */ 00239 Thread->NpxState = NPX_STATE_NOT_LOADED; 00240 00241 /* Setup the Stack for KiThreadStartup and Context Switching */ 00242 StartFrame = &InitFrame->StartFrame; 00243 CtxSwitchFrame = &InitFrame->CtxSwitchFrame; 00244 00245 /* Tell the thread it will run in Kernel Mode */ 00246 Thread->PreviousMode = KernelMode; 00247 00248 /* Tell KiThreadStartup of that too */ 00249 StartFrame->UserThread = FALSE; 00250 } 00251 00252 /* Now setup the remaining data for KiThreadStartup */ 00253 StartFrame->StartContext = StartContext; 00254 StartFrame->StartRoutine = StartRoutine; 00255 StartFrame->SystemRoutine = SystemRoutine; 00256 00257 /* And set up the Context Switch Frame */ 00258 CtxSwitchFrame->RetAddr = KiThreadStartup; 00259 CtxSwitchFrame->ApcBypassDisable = TRUE; 00260 CtxSwitchFrame->ExceptionList = EXCEPTION_CHAIN_END; 00261 00262 /* Save back the new value of the kernel stack. */ 00263 Thread->KernelStack = (PVOID)CtxSwitchFrame; 00264 } 00265 00266 VOID 00267 FASTCALL 00268 KiIdleLoop(VOID) 00269 { 00270 PKPRCB Prcb = KeGetCurrentPrcb(); 00271 PKTHREAD OldThread, NewThread; 00272 00273 /* Initialize the idle loop: disable interrupts */ 00274 _enable(); 00275 YieldProcessor(); 00276 YieldProcessor(); 00277 _disable(); 00278 00279 /* Now loop forever */ 00280 while (TRUE) 00281 { 00282 /* Check for pending timers, pending DPCs, or pending ready threads */ 00283 if ((Prcb->DpcData[0].DpcQueueDepth) || 00284 (Prcb->TimerRequest) || 00285 (Prcb->DeferredReadyListHead.Next)) 00286 { 00287 /* Quiesce the DPC software interrupt */ 00288 HalClearSoftwareInterrupt(DISPATCH_LEVEL); 00289 00290 /* Handle it */ 00291 KiRetireDpcList(Prcb); 00292 } 00293 00294 /* Check if a new thread is scheduled for execution */ 00295 if (Prcb->NextThread) 00296 { 00297 /* Enable interupts */ 00298 _enable(); 00299 00300 /* Capture current thread data */ 00301 OldThread = Prcb->CurrentThread; 00302 NewThread = Prcb->NextThread; 00303 00304 /* Set new thread data */ 00305 Prcb->NextThread = NULL; 00306 Prcb->CurrentThread = NewThread; 00307 00308 /* The thread is now running */ 00309 NewThread->State = Running; 00310 00311 /* Switch away from the idle thread */ 00312 KiSwapContext(APC_LEVEL, OldThread); 00313 00314 /* We are back in the idle thread -- disable interrupts again */ 00315 _enable(); 00316 YieldProcessor(); 00317 YieldProcessor(); 00318 _disable(); 00319 } 00320 else 00321 { 00322 /* Continue staying idle. Note the HAL returns with interrupts on */ 00323 Prcb->PowerState.IdleFunction(&Prcb->PowerState); 00324 } 00325 } 00326 } 00327 00328 BOOLEAN 00329 FASTCALL 00330 KiSwapContextExit(IN PKTHREAD OldThread, 00331 IN PKSWITCHFRAME SwitchFrame) 00332 { 00333 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 00334 PKPROCESS OldProcess, NewProcess; 00335 PKGDTENTRY GdtEntry; 00336 PKTHREAD NewThread; 00337 00338 /* We are on the new thread stack now */ 00339 NewThread = Pcr->PrcbData.CurrentThread; 00340 00341 /* Now we are the new thread. Check if it's in a new process */ 00342 OldProcess = OldThread->ApcState.Process; 00343 NewProcess = NewThread->ApcState.Process; 00344 if (OldProcess != NewProcess) 00345 { 00346 /* Check if there is a different LDT */ 00347 if (*(PULONGLONG)&OldProcess->LdtDescriptor != *(PULONGLONG)&NewProcess->LdtDescriptor) 00348 { 00349 DPRINT1("LDT switch not implemented\n"); 00350 ASSERT(FALSE); 00351 } 00352 00353 /* Switch address space and flush TLB */ 00354 __writecr3(NewProcess->DirectoryTableBase[0]); 00355 } 00356 00357 /* Clear GS */ 00358 Ke386SetGs(0); 00359 00360 /* Set the TEB */ 00361 Pcr->NtTib.Self = (PVOID)NewThread->Teb; 00362 GdtEntry = &Pcr->GDT[KGDT_R3_TEB / sizeof(KGDTENTRY)]; 00363 GdtEntry->BaseLow = (USHORT)((ULONG_PTR)NewThread->Teb & 0xFFFF); 00364 GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)NewThread->Teb >> 16); 00365 GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)NewThread->Teb >> 24); 00366 00367 /* Set new TSS fields */ 00368 Pcr->TSS->Esp0 = (ULONG_PTR)NewThread->InitialStack; 00369 if (!((KeGetTrapFrame(NewThread))->EFlags & EFLAGS_V86_MASK)) 00370 { 00371 Pcr->TSS->Esp0 -= (FIELD_OFFSET(KTRAP_FRAME, V86Gs) - FIELD_OFFSET(KTRAP_FRAME, HardwareSegSs)); 00372 } 00373 Pcr->TSS->Esp0 -= NPX_FRAME_LENGTH; 00374 Pcr->TSS->IoMapBase = NewProcess->IopmOffset; 00375 00376 /* Increase thread context switches */ 00377 NewThread->ContextSwitches++; 00378 00379 /* Load data from switch frame */ 00380 Pcr->NtTib.ExceptionList = SwitchFrame->ExceptionList; 00381 00382 /* DPCs shouldn't be active */ 00383 if (Pcr->PrcbData.DpcRoutineActive) 00384 { 00385 /* Crash the machine */ 00386 KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC, 00387 (ULONG_PTR)OldThread, 00388 (ULONG_PTR)NewThread, 00389 (ULONG_PTR)OldThread->InitialStack, 00390 0); 00391 } 00392 00393 /* Kernel APCs may be pending */ 00394 if (NewThread->ApcState.KernelApcPending) 00395 { 00396 /* Are APCs enabled? */ 00397 if (!NewThread->SpecialApcDisable) 00398 { 00399 /* Request APC delivery */ 00400 if (SwitchFrame->ApcBypassDisable) 00401 HalRequestSoftwareInterrupt(APC_LEVEL); 00402 else 00403 return TRUE; 00404 } 00405 } 00406 00407 /* Return stating that no kernel APCs are pending*/ 00408 return FALSE; 00409 } 00410 00411 VOID 00412 FASTCALL 00413 KiSwapContextEntry(IN PKSWITCHFRAME SwitchFrame, 00414 IN ULONG_PTR OldThreadAndApcFlag) 00415 { 00416 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 00417 PKTHREAD OldThread, NewThread; 00418 ULONG Cr0, NewCr0; 00419 00420 /* Save APC bypass disable */ 00421 SwitchFrame->ApcBypassDisable = OldThreadAndApcFlag & 3; 00422 SwitchFrame->ExceptionList = Pcr->NtTib.ExceptionList; 00423 00424 /* Increase context switch count and check if tracing is enabled */ 00425 Pcr->ContextSwitches++; 00426 if (Pcr->PerfGlobalGroupMask) 00427 { 00428 /* We don't support this yet on x86 either */ 00429 DPRINT1("WMI Tracing not supported\n"); 00430 ASSERT(FALSE); 00431 } 00432 00433 /* Get thread pointers */ 00434 OldThread = (PKTHREAD)(OldThreadAndApcFlag & ~3); 00435 NewThread = Pcr->PrcbData.CurrentThread; 00436 00437 /* Get the old thread and set its kernel stack */ 00438 OldThread->KernelStack = SwitchFrame; 00439 00440 /* ISRs can change FPU state, so disable interrupts while checking */ 00441 _disable(); 00442 00443 /* Get current and new CR0 and check if they've changed */ 00444 Cr0 = __readcr0(); 00445 NewCr0 = NewThread->NpxState | 00446 (Cr0 & ~(CR0_MP | CR0_EM | CR0_TS)) | 00447 KiGetThreadNpxArea(NewThread)->Cr0NpxState; 00448 if (Cr0 != NewCr0) __writecr0(NewCr0); 00449 00450 /* Now enable interrupts and do the switch */ 00451 _enable(); 00452 KiSwitchThreads(OldThread, NewThread->KernelStack); 00453 } 00454 00455 VOID 00456 NTAPI 00457 KiDispatchInterrupt(VOID) 00458 { 00459 PKIPCR Pcr = (PKIPCR)KeGetPcr(); 00460 PKPRCB Prcb = &Pcr->PrcbData; 00461 PVOID OldHandler; 00462 PKTHREAD NewThread, OldThread; 00463 00464 /* Disable interrupts */ 00465 _disable(); 00466 00467 /* Check for pending timers, pending DPCs, or pending ready threads */ 00468 if ((Prcb->DpcData[0].DpcQueueDepth) || 00469 (Prcb->TimerRequest) || 00470 (Prcb->DeferredReadyListHead.Next)) 00471 { 00472 /* Switch to safe execution context */ 00473 OldHandler = Pcr->NtTib.ExceptionList; 00474 Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END; 00475 00476 /* Retire DPCs while under the DPC stack */ 00477 KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack); 00478 00479 /* Restore context */ 00480 Pcr->NtTib.ExceptionList = OldHandler; 00481 } 00482 00483 /* Re-enable interrupts */ 00484 _enable(); 00485 00486 /* Check for quantum end */ 00487 if (Prcb->QuantumEnd) 00488 { 00489 /* Handle quantum end */ 00490 Prcb->QuantumEnd = FALSE; 00491 KiQuantumEnd(); 00492 } 00493 else if (Prcb->NextThread) 00494 { 00495 /* Capture current thread data */ 00496 OldThread = Prcb->CurrentThread; 00497 NewThread = Prcb->NextThread; 00498 00499 /* Set new thread data */ 00500 Prcb->NextThread = NULL; 00501 Prcb->CurrentThread = NewThread; 00502 00503 /* The thread is now running */ 00504 NewThread->State = Running; 00505 OldThread->WaitReason = WrDispatchInt; 00506 00507 /* Make the old thread ready */ 00508 KxQueueReadyThread(OldThread, Prcb); 00509 00510 /* Swap to the new thread */ 00511 KiSwapContext(APC_LEVEL, OldThread); 00512 } 00513 } 00514 00515 00516 /* EOF */ Generated on Fri May 25 2012 04:35:54 for ReactOS by
1.7.6.1
|