Doxygen

thrdini.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         ReactOS Kernel
00003  * LICENSE:         BSD - See COPYING.ARM in the top level directory
00004  * FILE:            ntoskrnl/ke/arm/thrdini.c
00005  * PURPOSE:         Implements thread context setup and startup for ARM machines
00006  * PROGRAMMERS:     ReactOS Portable Systems Group
00007  */
00008 
00009 /* INCLUDES *******************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 /* GLOBALS ********************************************************************/
00016 
00017 typedef struct _KSWITCHFRAME
00018 {
00019     PVOID ExceptionList;
00020     BOOLEAN ApcBypassDisable;
00021     PVOID RetAddr;
00022 } KSWITCHFRAME, *PKSWITCHFRAME;
00023 
00024 typedef struct _KUINIT_FRAME
00025 {
00026     KEXCEPTION_FRAME CtxSwitchFrame;
00027     KEXCEPTION_FRAME ExceptionFrame;
00028     KTRAP_FRAME TrapFrame;
00029 } KUINIT_FRAME, *PKUINIT_FRAME;
00030 
00031 typedef struct _KKINIT_FRAME
00032 {
00033     KEXCEPTION_FRAME CtxSwitchFrame;
00034 } KKINIT_FRAME, *PKKINIT_FRAME;
00035 
00036 /* FUNCTIONS ******************************************************************/
00037 
00038 VOID
00039 NTAPI
00040 KiThreadStartup(VOID);
00041 
00042 VOID
00043 FASTCALL
00044 KiSwitchThreads(
00045     IN PKTHREAD OldThread,
00046     IN PKTHREAD NewThread
00047 );
00048 
00049 
00050 /* FIXME: THIS IS TOTALLY BUSTED NOW */
00051 VOID
00052 NTAPI
00053 KiInitializeContextThread(IN PKTHREAD Thread,
00054                           IN PKSYSTEM_ROUTINE SystemRoutine,
00055                           IN PKSTART_ROUTINE StartRoutine,
00056                           IN PVOID StartContext,
00057                           IN PCONTEXT ContextPointer)
00058 {
00059     PKTRAP_FRAME TrapFrame;
00060     PKEXCEPTION_FRAME ExceptionFrame = NULL, CtxSwitchFrame;
00061 
00062     //
00063     // Check if this is a user thread
00064     //
00065     if (ContextPointer)
00066     {
00067         //
00068         // Setup the initial frame
00069         //
00070         PKUINIT_FRAME InitFrame;
00071         InitFrame = (PKUINIT_FRAME)((ULONG_PTR)Thread->InitialStack -
00072                                     sizeof(KUINIT_FRAME));
00073         
00074         //
00075         // Setup the Trap Frame and Exception frame
00076         //
00077         TrapFrame = &InitFrame->TrapFrame;
00078         ExceptionFrame = &InitFrame->ExceptionFrame;
00079         
00081         // Zero out the trap frame and exception frame
00082         //
00083         RtlZeroMemory(TrapFrame, sizeof(KTRAP_FRAME));
00084         RtlZeroMemory(ExceptionFrame, sizeof(KEXCEPTION_FRAME));
00085                 
00086         //
00087         // Set up a trap frame from the context
00088         //
00089         KeContextToTrapFrame(ContextPointer,
00090                              ExceptionFrame,
00091                              TrapFrame,
00092                              ContextPointer->ContextFlags | CONTEXT_CONTROL,
00093                              UserMode);
00094 
00095         //
00096         // Set the previous mode as user
00097         //
00098         //TrapFrame->PreviousMode = UserMode;
00099         Thread->PreviousMode = UserMode;
00100         
00101         //
00102         // Clear the return address
00103         //
00104         ExceptionFrame->Lr = 0;
00105         
00106         //
00107         // Context switch frame to setup below
00108         //
00109         CtxSwitchFrame = &InitFrame->CtxSwitchFrame;
00110     }
00111     else
00112     {
00113         //
00114         // Set up the Initial Frame for the system thread
00115         //
00116         PKKINIT_FRAME InitFrame;
00117         InitFrame = (PKKINIT_FRAME)((ULONG_PTR)Thread->InitialStack -
00118                                     sizeof(KKINIT_FRAME));
00119         
00120         //
00121         // Set the previous mode as kernel
00122         //
00123         Thread->PreviousMode = KernelMode;
00124         
00125         //
00126         // Context switch frame to setup below
00127         //
00128         CtxSwitchFrame = &InitFrame->CtxSwitchFrame;
00129     }
00130     
00131     //
00132     // Now setup the context switch frame
00133     //
00134     CtxSwitchFrame->Lr = (ULONG)KiThreadStartup;
00135     CtxSwitchFrame->R11 = (ULONG)(ExceptionFrame ? ExceptionFrame : CtxSwitchFrame);
00136 
00137     //
00138     // Set the parameters
00139     //
00140     CtxSwitchFrame->R4 = (ULONG)ContextPointer;
00141     CtxSwitchFrame->R5 = (ULONG)StartContext;
00142     CtxSwitchFrame->R6 = (ULONG)StartRoutine;
00143     CtxSwitchFrame->R7 = (ULONG)SystemRoutine;
00144     
00145     //
00146     // Save back the new value of the kernel stack
00147     //
00148     Thread->KernelStack = (PVOID)CtxSwitchFrame;
00149 }
00150 
00151 VOID
00152 FASTCALL
00153 KiIdleLoop(VOID)
00154 {
00155     PKPRCB Prcb = KeGetCurrentPrcb();
00156     PKTHREAD OldThread, NewThread;
00157 
00158     /* Initialize the idle loop: disable interrupts */
00159     _enable();
00160     YieldProcessor();
00161     YieldProcessor();
00162     _disable();
00163 
00164     /* Now loop forever */
00165     while (TRUE)
00166     {
00167         /* Check for pending timers, pending DPCs, or pending ready threads */
00168         if ((Prcb->DpcData[0].DpcQueueDepth) ||
00169             (Prcb->TimerRequest) ||
00170             (Prcb->DeferredReadyListHead.Next))
00171         {
00172             /* Quiesce the DPC software interrupt */
00173             HalClearSoftwareInterrupt(DISPATCH_LEVEL);
00174 
00175             /* Handle it */
00176             KiRetireDpcList(Prcb);
00177         }
00178 
00179         /* Check if a new thread is scheduled for execution */
00180         if (Prcb->NextThread)
00181         {
00182             /* Enable interupts */
00183             _enable();
00184 
00185             /* Capture current thread data */
00186             OldThread = Prcb->CurrentThread;
00187             NewThread = Prcb->NextThread;
00188 
00189             /* Set new thread data */
00190             Prcb->NextThread = NULL;
00191             Prcb->CurrentThread = NewThread;
00192 
00193             /* The thread is now running */
00194             NewThread->State = Running;
00195 
00196             /* Switch away from the idle thread */
00197             KiSwapContext(APC_LEVEL, OldThread);
00198 
00199             /* We are back in the idle thread -- disable interrupts again */
00200             _enable();
00201             YieldProcessor();
00202             YieldProcessor();
00203             _disable();
00204         }
00205         else
00206         {
00207             /* Continue staying idle. Note the HAL returns with interrupts on */
00208             Prcb->PowerState.IdleFunction(&Prcb->PowerState);
00209         }
00210     }
00211 }
00212 
00213 BOOLEAN
00214 FASTCALL
00215 KiSwapContextExit(IN PKTHREAD OldThread,
00216                   IN PKSWITCHFRAME SwitchFrame)
00217 {
00218     PKIPCR Pcr = (PKIPCR)KeGetPcr();
00219     PKPROCESS OldProcess, NewProcess;
00220     PKTHREAD NewThread;
00221     ARM_TTB_REGISTER TtbRegister;
00222 
00223     /* We are on the new thread stack now */
00224     NewThread = Pcr->PrcbData.CurrentThread;
00225 
00226     /* Now we are the new thread. Check if it's in a new process */
00227     OldProcess = OldThread->ApcState.Process;
00228     NewProcess = NewThread->ApcState.Process;
00229     if (OldProcess != NewProcess)
00230     {
00231         TtbRegister.AsUlong = NewProcess->DirectoryTableBase[0];
00232         ASSERT(TtbRegister.Reserved == 0);
00233         KeArmTranslationTableRegisterSet(TtbRegister);
00234     }
00235 
00236     /* Increase thread context switches */
00237     NewThread->ContextSwitches++;
00238 
00239     /* Load data from switch frame */
00240     Pcr->NtTib.ExceptionList = SwitchFrame->ExceptionList;
00241 
00242     /* DPCs shouldn't be active */
00243     if (Pcr->PrcbData.DpcRoutineActive)
00244     {
00245         /* Crash the machine */
00246         KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC,
00247                      (ULONG_PTR)OldThread,
00248                      (ULONG_PTR)NewThread,
00249                      (ULONG_PTR)OldThread->InitialStack,
00250                      0);
00251     }
00252 
00253     /* Kernel APCs may be pending */
00254     if (NewThread->ApcState.KernelApcPending)
00255     {
00256         /* Are APCs enabled? */
00257         if (!NewThread->SpecialApcDisable)
00258         {
00259             /* Request APC delivery */
00260             if (SwitchFrame->ApcBypassDisable) HalRequestSoftwareInterrupt(APC_LEVEL);
00261             return TRUE;
00262         }
00263     }
00264 
00265     /* Return */
00266     return FALSE;
00267 }
00268 
00269 VOID
00270 FASTCALL
00271 KiSwapContextEntry(IN PKSWITCHFRAME SwitchFrame,
00272                    IN ULONG_PTR OldThreadAndApcFlag)
00273 {
00274     PKIPCR Pcr = (PKIPCR)KeGetPcr();
00275     PKTHREAD OldThread, NewThread;
00276 
00277     /* Save APC bypass disable */
00278     SwitchFrame->ApcBypassDisable = OldThreadAndApcFlag & 3;
00279     SwitchFrame->ExceptionList = Pcr->NtTib.ExceptionList;
00280 
00281     /* Increase context switch count and check if tracing is enabled */
00282     Pcr->ContextSwitches++;
00283     if (Pcr->PerfGlobalGroupMask)
00284     {
00285         /* We don't support this yet on x86 either */
00286         DPRINT1("WMI Tracing not supported\n");
00287         ASSERT(FALSE);
00288     }
00289 
00290     /* Get thread pointers */
00291     OldThread = (PKTHREAD)(OldThreadAndApcFlag & ~3);
00292     NewThread = Pcr->PrcbData.CurrentThread;
00293 
00294     /* Get the old thread and set its kernel stack */
00295     OldThread->KernelStack = SwitchFrame;
00296 
00297     /* Do the switch */
00298     KiSwitchThreads(OldThread, NewThread->KernelStack);
00299 }
00300 
00301 VOID
00302 NTAPI
00303 KiDispatchInterrupt(VOID)
00304 {
00305     PKIPCR Pcr = (PKIPCR)KeGetPcr();
00306     PKPRCB Prcb = &Pcr->PrcbData;
00307     PVOID OldHandler;
00308     PKTHREAD NewThread, OldThread;
00309 
00310     /* Disable interrupts */
00311     _disable();
00312 
00313     /* Check for pending timers, pending DPCs, or pending ready threads */
00314     if ((Prcb->DpcData[0].DpcQueueDepth) ||
00315         (Prcb->TimerRequest) ||
00316         (Prcb->DeferredReadyListHead.Next))
00317     {
00318         /* Switch to safe execution context */
00319         OldHandler = Pcr->NtTib.ExceptionList;
00320         Pcr->NtTib.ExceptionList = EXCEPTION_CHAIN_END;
00321 
00322         /* Retire DPCs while under the DPC stack */
00323         //KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack);
00324         // FIXME!!! //
00325         KiRetireDpcList(Prcb);
00326 
00327         /* Restore context */
00328         Pcr->NtTib.ExceptionList = OldHandler;
00329     }
00330 
00331     /* Re-enable interrupts */
00332     _enable();
00333 
00334     /* Check for quantum end */
00335     if (Prcb->QuantumEnd)
00336     {
00337         /* Handle quantum end */
00338         Prcb->QuantumEnd = FALSE;
00339         KiQuantumEnd();
00340     }
00341     else if (Prcb->NextThread)
00342     {       
00343         /* Capture current thread data */
00344         OldThread = Prcb->CurrentThread;
00345         NewThread = Prcb->NextThread;
00346 
00347         /* Set new thread data */
00348         Prcb->NextThread = NULL;
00349         Prcb->CurrentThread = NewThread;
00350 
00351         /* The thread is now running */
00352         NewThread->State = Running;
00353         OldThread->WaitReason = WrDispatchInt;
00354 
00355         /* Make the old thread ready */
00356         KxQueueReadyThread(OldThread, Prcb);
00357 
00358         /* Swap to the new thread */
00359         KiSwapContext(APC_LEVEL, OldThread);
00360     }
00361 }
00362 
00363 /* EOF */