ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

thrdini.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.