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->Return = 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->Return = (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->Prcb.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     /* DPCs shouldn't be active */
00240     if (Pcr->Prcb.DpcRoutineActive)
00241     {
00242         /* Crash the machine */
00243         KeBugCheckEx(ATTEMPTED_SWITCH_FROM_DPC,
00244                      (ULONG_PTR)OldThread,
00245                      (ULONG_PTR)NewThread,
00246                      (ULONG_PTR)OldThread->InitialStack,
00247                      0);
00248     }
00249 
00250     /* Kernel APCs may be pending */
00251     if (NewThread->ApcState.KernelApcPending)
00252     {
00253         /* Are APCs enabled? */
00254         if (!NewThread->SpecialApcDisable)
00255         {
00256             /* Request APC delivery */
00257             if (SwitchFrame->ApcBypassDisable) HalRequestSoftwareInterrupt(APC_LEVEL);
00258             return TRUE;
00259         }
00260     }
00261 
00262     /* Return */
00263     return FALSE;
00264 }
00265 
00266 VOID
00267 FASTCALL
00268 KiSwapContextEntry(IN PKSWITCHFRAME SwitchFrame,
00269                    IN ULONG_PTR OldThreadAndApcFlag)
00270 {
00271     PKIPCR Pcr = (PKIPCR)KeGetPcr();
00272     PKTHREAD OldThread, NewThread;
00273 
00274     /* Save APC bypass disable */
00275     SwitchFrame->ApcBypassDisable = OldThreadAndApcFlag & 3;
00276 
00277     /* Increase context switch count and check if tracing is enabled */
00278     Pcr->Prcb.KeContextSwitches++;
00279 #if 0
00280     if (Pcr->PerfGlobalGroupMask)
00281     {
00282         /* We don't support this yet on x86 either */
00283         DPRINT1("WMI Tracing not supported\n");
00284         ASSERT(FALSE);
00285     }
00286 #endif // 0
00287 
00288     /* Get thread pointers */
00289     OldThread = (PKTHREAD)(OldThreadAndApcFlag & ~3);
00290     NewThread = Pcr->Prcb.CurrentThread;
00291 
00292     /* Get the old thread and set its kernel stack */
00293     OldThread->KernelStack = SwitchFrame;
00294 
00295     /* Do the switch */
00296     KiSwitchThreads(OldThread, NewThread->KernelStack);
00297 }
00298 
00299 VOID
00300 NTAPI
00301 KiDispatchInterrupt(VOID)
00302 {
00303     PKIPCR Pcr = (PKIPCR)KeGetPcr();
00304     PKPRCB Prcb = &Pcr->Prcb;
00305     PKTHREAD NewThread, OldThread;
00306 
00307     /* Disable interrupts */
00308     _disable();
00309 
00310     /* Check for pending timers, pending DPCs, or pending ready threads */
00311     if ((Prcb->DpcData[0].DpcQueueDepth) ||
00312         (Prcb->TimerRequest) ||
00313         (Prcb->DeferredReadyListHead.Next))
00314     {
00315         /* Retire DPCs while under the DPC stack */
00316         //KiRetireDpcListInDpcStack(Prcb, Prcb->DpcStack);
00317         // FIXME!!! //
00318         KiRetireDpcList(Prcb);
00319     }
00320 
00321     /* Re-enable interrupts */
00322     _enable();
00323 
00324     /* Check for quantum end */
00325     if (Prcb->QuantumEnd)
00326     {
00327         /* Handle quantum end */
00328         Prcb->QuantumEnd = FALSE;
00329         KiQuantumEnd();
00330     }
00331     else if (Prcb->NextThread)
00332     {
00333         /* Capture current thread data */
00334         OldThread = Prcb->CurrentThread;
00335         NewThread = Prcb->NextThread;
00336 
00337         /* Set new thread data */
00338         Prcb->NextThread = NULL;
00339         Prcb->CurrentThread = NewThread;
00340 
00341         /* The thread is now running */
00342         NewThread->State = Running;
00343         OldThread->WaitReason = WrDispatchInt;
00344 
00345         /* Make the old thread ready */
00346         KxQueueReadyThread(OldThread, Prcb);
00347 
00348         /* Swap to the new thread */
00349         KiSwapContext(APC_LEVEL, OldThread);
00350     }
00351 }
00352 
00353 /* EOF */