test: thredini.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# thredini.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1990  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     thredini.c
    00008
    00009 Abstract:
    00010
    00011     This module implements the machine dependent function to set the initial
    00012     context and data alignment handling mode for a process or thread object.
    00013
    00014 Author:
    00015
    00016     David N. Cutler (davec) 31-Mar-1990
    00017
    00018 Environment:
    00019
    00020     Kernel mode only.
    00021
    00022 Revision History:
    00023
    00024     3 April 90  bryan willman
    00025
    00026         This version ported to 386.
    00027
    00028 --*/
    00029
    00030 #include "ki.h"
    00031
    00032 //
    00033 // The following assert macros are used to check that an input object is
    00034 // really the proper type.
    00035 //
    00036
    00037 #define ASSERT_PROCESS(E) {                    \
    00038     ASSERT((E)->Header.Type == ProcessObject); \
    00039 }
    00040
    00041 #define ASSERT_THREAD(E) {                    \
    00042     ASSERT((E)->Header.Type == ThreadObject); \
    00043 }
    00044
    00045 //
    00046 // Our notion of alignment is different, so force use of ours
    00047 //
    00048 #undef  ALIGN_UP
    00049 #undef  ALIGN_DOWN
    00050 #define ALIGN_DOWN(address,amt) ((ULONG)(address) & ~(( amt ) - 1))
    00051 #define ALIGN_UP(address,amt) (ALIGN_DOWN( (address + (amt) - 1), (amt) ))
    00052
    00053 //
    00054 // The function prototype for the special APC we use to set the
    00055 // hardware alignment state for a thread
    00056 //
    00057
    00058 VOID
    00059 KepSetAlignmentSpecialApc(
    00060     IN PKAPC Apc,
    00061     IN PKNORMAL_ROUTINE *NormalRoutine,
    00062     IN PVOID *NormalContext,
    00063     IN PVOID *SystemArgument1,
    00064     IN PVOID *SystemArgument2
    00065     );
    00066
    00067 extern BOOLEAN KeI386XMMIPresent;
    00068
    00069
    00070 VOID
    00071 KiInitializeContextThread (
    00072     IN PKTHREAD Thread,
    00073     IN PKSYSTEM_ROUTINE SystemRoutine,
    00074     IN PKSTART_ROUTINE StartRoutine OPTIONAL,
    00075     IN PVOID StartContext OPTIONAL,
    00076     IN PCONTEXT ContextFrame OPTIONAL
    00077     )
    00078
    00079 /*++
    00080
    00081 Routine Description:
    00082
    00083     This function initializes the machine dependent context of a thread object.
    00084
    00085     N.B. This function does not check the accessibility of the context record.
    00086          It is assumed the the caller of this routine is either prepared to
    00087          handle access violations or has probed and copied the context record
    00088          as appropriate.
    00089
    00090 Arguments:
    00091
    00092     Thread - Supplies a pointer to a dispatcher object of type thread.
    00093
    00094     SystemRoutine - Supplies a pointer to the system function that is to be
    00095         called when the thread is first scheduled for execution.
    00096
    00097     StartRoutine - Supplies an optional pointer to a function that is to be
    00098         called after the system has finished initializing the thread. This
    00099         parameter is specified if the thread is a system thread and will
    00100         execute totally in kernel mode.
    00101
    00102     StartContext - Supplies an optional pointer to an arbitrary data structure
    00103         which will be passed to the StartRoutine as a parameter. This
    00104         parameter is specified if the thread is a system thread and will
    00105         execute totally in kernel mode.
    00106
    00107     ContextFrame - Supplies an optional pointer a context frame which contains
    00108         the initial user mode state of the thread. This parameter is specified
    00109         if the thread is a user thread and will execute in user mode. If this
    00110         parameter is not specified, then the Teb parameter is ignored.
    00111
    00112 Return Value:
    00113
    00114     None.
    00115
    00116 --*/
    00117
    00118 {
    00119     PFX_SAVE_AREA NpxFrame;
    00120     PKSWITCHFRAME SwitchFrame;
    00121     PKTRAP_FRAME TrFrame;
    00122     PULONG PSystemRoutine;
    00123     PULONG PStartRoutine;
    00124     PULONG PStartContext;
    00125     PULONG PUserContextFlag;
    00126     ULONG  ContextFlags;
    00127     CONTEXT Context2;
    00128     PCONTEXT ContextFrame2 = NULL;
    00129     PFXSAVE_FORMAT   PFxSaveArea;
    00130
    00131     //
    00132     // If a context frame is specified, then initialize a trap frame and
    00133     // and an exception frame with the specified user mode context.
    00134     //
    00135
    00136     if (ARGUMENT_PRESENT(ContextFrame)) {
    00137
    00138         RtlMoveMemory(&Context2, ContextFrame, sizeof(CONTEXT));
    00139         ContextFrame2 = &Context2;
    00140         ContextFlags = CONTEXT_CONTROL;
    00141
    00142         //
    00143         // The 80387 save area is at the very base of the kernel stack.
    00144         //
    00145
    00146         NpxFrame = (PFX_SAVE_AREA)(((ULONG)(Thread->InitialStack) -
    00147                     sizeof(FX_SAVE_AREA)));
    00148
    00149         //
    00150         // Load up an initial NPX state.
    00151         //
    00152
    00153         if (KeI386XMMIPresent == TRUE) {
    00154             PFxSaveArea = (PFXSAVE_FORMAT)ContextFrame2->ExtendedRegisters;
    00155
    00156             PFxSaveArea->ControlWord   = 0x27f;  // like fpinit but 64bit mode
    00157             PFxSaveArea->StatusWord    = 0;
    00158             PFxSaveArea->TagWord       = 0;
    00159             PFxSaveArea->ErrorOffset   = 0;
    00160             PFxSaveArea->ErrorSelector = 0;
    00161             PFxSaveArea->DataOffset    = 0;
    00162             PFxSaveArea->DataSelector  = 0;
    00163             PFxSaveArea->MXCsr         = 0x1f80; // mask all the exceptions
    00164         } else {
    00165             ContextFrame2->FloatSave.ControlWord   = 0x27f;  // like fpinit but 64bit mode
    00166             ContextFrame2->FloatSave.StatusWord    = 0;
    00167             ContextFrame2->FloatSave.TagWord       = 0xffff;
    00168             ContextFrame2->FloatSave.ErrorOffset   = 0;
    00169             ContextFrame2->FloatSave.ErrorSelector = 0;
    00170             ContextFrame2->FloatSave.DataOffset    = 0;
    00171             ContextFrame2->FloatSave.DataSelector  = 0;
    00172         }
    00173
    00174
    00175         if (KeI386NpxPresent) {
    00176             ContextFrame2->FloatSave.Cr0NpxState = 0;
    00177             NpxFrame->Cr0NpxState = 0;
    00178             NpxFrame->NpxSavedCpu = 0;
    00179             if (KeI386XMMIPresent == TRUE) {
    00180                 ContextFlags |= CONTEXT_EXTENDED_REGISTERS;
    00181             } else {
    00182                 ContextFlags |= CONTEXT_FLOATING_POINT;
    00183             }
    00184
    00185             //
    00186             // Threads NPX state is not in the coprocessor.
    00187             //
    00188
    00189             Thread->NpxState = NPX_STATE_NOT_LOADED;
    00190             Thread->NpxIrql = PASSIVE_LEVEL;
    00191
    00192         } else {
    00193             NpxFrame->Cr0NpxState = CR0_EM;
    00194
    00195             //
    00196             // Threads NPX state is not in the coprocessor.
    00197             // In the emulator case, do not set the CR0_EM bit as their
    00198             // emulators may not want exceptions on FWAIT instructions.
    00199             //
    00200
    00201             Thread->NpxState = NPX_STATE_NOT_LOADED & ~CR0_MP;
    00202         }
    00203
    00204         //
    00205         // Force debug registers off.  They won't work anyway from an
    00206         // initial frame, debuggers must set a hard breakpoint in the target
    00207         //
    00208
    00209         ContextFrame2->Dr0 = 0;
    00210         ContextFrame2->Dr1 = 0;
    00211         ContextFrame2->Dr2 = 0;
    00212         ContextFrame2->Dr3 = 0;
    00213         ContextFrame2->Dr6 = 0;
    00214         ContextFrame2->Dr7 = 0;
    00215         ContextFrame2->ContextFlags &= ~(CONTEXT_DEBUG_REGISTERS);
    00216 #if 0
    00217         //
    00218         // If AutoAlignment is FALSE, we want to set the Alignment Check bit
    00219         // in Eflags, so we will get alignment faults.
    00220         //
    00221
    00222         if (Thread->AutoAlignment == FALSE) {
    00223             ContextFrame2->EFlags |= EFLAGS_ALIGN_CHECK;
    00224         }
    00225 #endif
    00226         //
    00227         // If the thread is set
    00228
    00229         TrFrame = (PKTRAP_FRAME)(((ULONG)NpxFrame - KTRAP_FRAME_LENGTH));
    00230
    00231         //  Space for arguments to KiThreadStartup.  Order is important,
    00232         //  Since args are passed on stack through KiThreadStartup to
    00233         //  PStartRoutine with PStartContext as an argument.
    00234
    00235         PUserContextFlag = (PULONG)TrFrame - 1;
    00236         PStartContext = PUserContextFlag - 1;
    00237         PStartRoutine = PStartContext - 1;
    00238         PSystemRoutine = PStartRoutine - 1;
    00239
    00240         SwitchFrame = (PKSWITCHFRAME)((PUCHAR)PSystemRoutine -
    00241                                     sizeof(KSWITCHFRAME));
    00242
    00243         //
    00244         // Copy information from the specified context frame to the trap and
    00245         // exception frames.
    00246         //
    00247
    00248         KeContextToKframes(TrFrame, NULL, ContextFrame2,
    00249                            ContextFrame2->ContextFlags | ContextFlags,
    00250                            UserMode);
    00251
    00252         TrFrame->HardwareSegSs |= RPL_MASK;
    00253         TrFrame->SegDs |= RPL_MASK;
    00254         TrFrame->SegEs |= RPL_MASK;
    00255
    00256 #if DBG
    00257         TrFrame->DbgArgMark = 0xBADB0D00;
    00258 #endif
    00259
    00260         //
    00261         // Tell KiThreadStartup that a user context is present.
    00262         //
    00263
    00264         *PUserContextFlag = 1;
    00265
    00266
    00267         //
    00268         // Initialize the kernel mode ExceptionList pointer
    00269         //
    00270
    00271         TrFrame->ExceptionList = EXCEPTION_CHAIN_END;
    00272
    00273         //
    00274         // Initialize the saved previous processor mode.
    00275         //
    00276
    00277         TrFrame->PreviousPreviousMode = UserMode;
    00278
    00279         //
    00280         // Set the previous mode in thread object to user.
    00281         //
    00282
    00283         Thread->PreviousMode = UserMode;
    00284
    00285
    00286     } else {
    00287
    00288         //
    00289         // Dummy floating save area.  Kernel threads don't have or use
    00290         // the floating point - the dummy save area is make the stacks
    00291         // consistent.
    00292         //
    00293
    00294         NpxFrame = (PFX_SAVE_AREA)(((ULONG)(Thread->InitialStack) -
    00295                     sizeof(FX_SAVE_AREA)));
    00296
    00297         //
    00298         // Load up an initial NPX state.
    00299         //
    00300         RtlZeroMemory((PVOID)NpxFrame, sizeof(FX_SAVE_AREA));
    00301
    00302         if (KeI386FxsrPresent == TRUE) {
    00303             NpxFrame->U.FxArea.ControlWord = 0x27f;//like fpinit but 64bit mode
    00304             NpxFrame->U.FxArea.MXCsr       = 0x1f80;// mask all the exceptions
    00305         } else {
    00306             NpxFrame->U.FnArea.ControlWord  = 0x27f;//like fpinit but 64bit mode
    00307             NpxFrame->U.FnArea.TagWord      = 0xffff;
    00308         }
    00309
    00310         //
    00311         // Threads NPX state is not in the coprocessor.
    00312         //
    00313
    00314         Thread->NpxState = NPX_STATE_NOT_LOADED;
    00315
    00316         //
    00317         //  Space for arguments to KiThreadStartup.
    00318         //  Order of fields in the switchframe is important,
    00319         //  Since args are passed on stack through KiThreadStartup to
    00320         //  PStartRoutine with PStartContext as an argument.
    00321         //
    00322
    00323         PUserContextFlag = (PULONG)((ULONG)NpxFrame) - 1;
    00324
    00325         PStartContext = PUserContextFlag - 1;
    00326         PStartRoutine = PStartContext - 1;
    00327         PSystemRoutine = PStartRoutine - 1;
    00328
    00329         SwitchFrame = (PKSWITCHFRAME)((PUCHAR)PSystemRoutine -
    00330                                         sizeof(KSWITCHFRAME));
    00331
    00332
    00333         //
    00334         // Tell KiThreadStartup that a user context is NOT present.
    00335         //
    00336
    00337         *PUserContextFlag = 0;
    00338
    00339
    00340         //
    00341         // Set the previous mode in thread object to kernel.
    00342         //
    00343
    00344         Thread->PreviousMode = KernelMode;
    00345     }
    00346
    00347     //
    00348     //  Set up thread start parameters.
    00349     //  (UserContextFlag set above)
    00350     //
    00351
    00352     *PStartContext = (ULONG)StartContext;
    00353     *PStartRoutine = (ULONG)StartRoutine;
    00354     *PSystemRoutine = (ULONG)SystemRoutine;
    00355
    00356
    00357     //
    00358     //  Set up switch frame.  Assume the thread doesn't use the 80387;
    00359     //  if it ever does (and there is one), these flags will get reset.
    00360     //  Each thread starts with these same flags set, regardless of
    00361     //  whether the hardware exists or not.
    00362     //
    00363
    00364     SwitchFrame->RetAddr = (ULONG)KiThreadStartup;
    00365
    00366     SwitchFrame->Eflags = EFLAGS_INTERRUPT_MASK;
    00367
    00368 #if 0
    00369     //
    00370     // If AutoAlignment is FALSE, we want to set the Alignment Check bit
    00371     // in Eflags, so we will get alignment faults.
    00372     //
    00373
    00374     if (Thread->AutoAlignment == FALSE) {
    00375         SwitchFrame->Eflags |= EFLAGS_ALIGN_CHECK;
    00376     }
    00377 #endif
    00378
    00379     SwitchFrame->ExceptionList = (ULONG)(EXCEPTION_CHAIN_END);
    00380
    00381     //
    00382     // Set the initial kernel stack pointer.
    00383     //
    00384
    00385 //DbgPrint("KiInitializeContextThread Thread %08x  SwitchFrame %08x\n", Thread, SwitchFrame);
    00386 //DbgPrint("PSystemRoutine %08x  PStartRoutine %08x  PStartContext %08x\n", *PSystemRoutine, *PStartRoutine, *PStartContext);
    00387
    00388     Thread->KernelStack = (PVOID)SwitchFrame;
    00389     return;
    00390 }
    00391
    00392 BOOLEAN
    00393 KeSetAutoAlignmentProcess (
    00394     IN PKPROCESS Process,
    00395     IN BOOLEAN Enable
    00396     )
    00397
    00398 /*++
    00399
    00400 Routine Description:
    00401
    00402     This function sets the data alignment handling mode for the specified
    00403     process and returns the previous data alignment handling mode.
    00404
    00405 Arguments:
    00406
    00407     Process  - Supplies a pointer to a dispatcher object of type process.
    00408
    00409     Enable - Supplies a boolean value that determines the handling of data
    00410         alignment exceptions for the process. A value of TRUE causes all
    00411         data alignment exceptions to be automatically handled by the kernel.
    00412         A value of FALSE causes all data alignment exceptions to be actually
    00413         raised as exceptions.
    00414
    00415 Return Value:
    00416
    00417     A value of TRUE is returned if data alignment exceptions were
    00418     previously automatically handled by the kernel. Otherwise, a value
    00419     of FALSE is returned.
    00420
    00421 --*/
    00422
    00423 {
    00424
    00425     KIRQL OldIrql;
    00426     BOOLEAN Previous;
    00427
    00428     ASSERT_PROCESS(Process);
    00429
    00430     //
    00431     // Raise IRQL to dispatcher level and lock dispatcher database.
    00432     //
    00433
    00434     KiLockDispatcherDatabase(&OldIrql);
    00435
    00436     //
    00437     // Capture the previous data alignment handling mode and set the
    00438     // specified data alignment mode.
    00439     //
    00440
    00441     Previous = Process->AutoAlignment;
    00442     Process->AutoAlignment = Enable;
    00443
    00444     //
    00445     // Unlock dispatcher database, lower IRQL to its previous value, and
    00446     // return the previous data alignment mode.
    00447     //
    00448
    00449     KiUnlockDispatcherDatabase(OldIrql);
    00450     return Previous;
    00451 }
    00452
    00453 BOOLEAN
    00454 KeSetAutoAlignmentThread (
    00455     IN PKTHREAD Thread,
    00456     IN BOOLEAN Enable
    00457     )
    00458
    00459 /*++
    00460
    00461 Routine Description:
    00462
    00463     This function sets the data alignment handling mode for the specified
    00464     thread and returns the previous data alignment handling mode.
    00465
    00466 Arguments:
    00467
    00468     Thread - Supplies a pointer to a dispatcher object of type thread.
    00469
    00470     Enable - Supplies a boolean value that determines the handling of data
    00471         alignment exceptions for the specified thread. A value of TRUE causes
    00472         all data alignment exceptions to be automatically handled by the kernel.
    00473         A value of FALSE causes all data alignment exceptions to be actually
    00474         raised as exceptions.
    00475
    00476 Return Value:
    00477
    00478     A value of TRUE is returned if data alignment exceptions were
    00479     previously automatically handled by the kernel. Otherwise, a value
    00480     of FALSE is returned.
    00481
    00482 --*/
    00483
    00484 {
    00485
    00486     BOOLEAN Previous;
    00487     PKAPC Apc;
    00488     PKEVENT Event;
    00489     KIRQL OldIrql;
    00490
    00491     ASSERT_THREAD(Thread);
    00492
    00493     //
    00494     // Raise IRQL to dispatcher level and lock dispatcher database.
    00495     //
    00496
    00497     KiLockDispatcherDatabase(&OldIrql);
    00498
    00499     //
    00500     // Capture the previous data alignment handling mode and set the
    00501     // specified data alignment mode.
    00502     //
    00503
    00504     Previous = Thread->AutoAlignment;
    00505     Thread->AutoAlignment = Enable;
    00506
    00507     //
    00508     // Unlock dispatcher database and lower IRQL to its previous value.
    00509     //
    00510
    00511     KiUnlockDispatcherDatabase(OldIrql);
    00512
    00513 #if 0
    00514     Apc = ExAllocatePool(NonPagedPoolMustSucceed, sizeof(KAPC));
    00515     Event = ExAllocatePool(NonPagedPoolMustSucceed, sizeof(KEVENT));
    00516
    00517     KeInitializeEvent(Event, NotificationEvent, FALSE);
    00518
    00519     if ( Thread == KeGetCurrentThread() ) {
    00520
    00521         Apc->SystemArgument1 = Thread;
    00522         Apc->SystemArgument2 = Event;
    00523
    00524         KeRaiseIrql(APC_LEVEL, &Irql);
    00525         KepSetAlignmentSpecialApc( Apc, NULL, NULL,
    00526                                    &Apc->SystemArgument1,
    00527                                    &Apc->SystemArgument2 );
    00528         KeLowerIrql(Irql);
    00529     } else {
    00530         KeInitializeApc( Apc,
    00531                          Thread,
    00532                          CurrentApcEnvironment,
    00533                          KepSetAlignmentSpecialApc,
    00534                          NULL,
    00535                          NULL,
    00536                          KernelMode,
    00537                          NULL );
    00538
    00539         if (!KeInsertQueueApc( Apc,
    00540                                Thread,
    00541                                Event,
    00542                                2 ) ) {
    00543             //
    00544             // We couldn't queue the APC, so we will not be able to change
    00545             // the AutoAlignment.  Update the thread object so that it
    00546             // stays in sync with the hardware state.
    00547             //
    00548 #if DBG
    00549             DbgPrint("KeSetAutoAlignmentThread: unable to change thread's context\n");
    00550 #endif
    00551             Thread->AutoAlignment = Previous;
    00552         }
    00553
    00554         KeWaitForSingleObject( Event,
    00555                                Executive,
    00556                                KernelMode,
    00557                                FALSE,
    00558                                NULL );
    00559     }
    00560
    00561     ExFreePool(Apc);
    00562     ExFreePool(Event);
    00563 #endif
    00564
    00565     return(Previous);
    00566 }
    00567
    00568 #if 0
    00569
    00570 VOID
    00571 KepSetAlignmentSpecialApc(
    00572     IN PKAPC Apc,
    00573     IN PKNORMAL_ROUTINE *NormalRoutine,
    00574     IN PVOID *NormalContext,
    00575     IN PVOID *SystemArgument1,
    00576     IN PVOID *SystemArgument2
    00577     )
    00578
    00579 /*++
    00580
    00581 Routine Description:
    00582
    00583     This function updates the alignment check bit of the current thread's
    00584     EFLAGS to reflect the AutoAlignment setting of the thread object.
    00585
    00586 Arguments:
    00587
    00588     Apc - Supplies a pointer to the APC control object that caused entry
    00589           into this routine.
    00590
    00591     NormalRoutine - Supplies a pointer to a pointer to the normal routine
    00592         function that was specifed when the APC was initialized.
    00593
    00594     NormalContext - Supplies a pointer to a pointer to an arbitrary data
    00595         structure that was specified when the APC was initialized.
    00596
    00597     SystemArgument1 - Supplies a pointer to a PKTHREAD
    00598
    00599     SystemArgument2 - Supplies a pointer to a PKEVENT
    00600
    00601 Return Value:
    00602
    00603     None.
    00604
    00605 --*/
    00606
    00607 {
    00608     PKTHREAD Thread;
    00609     PKEVENT Event;
    00610     PKTRAP_FRAME TrapFrame;
    00611     CONTEXT ContextFrame;
    00612
    00613     Thread = *(PKTHREAD *)SystemArgument1;
    00614     Event = *(PKEVENT *)SystemArgument2;
    00615
    00616     ASSERT( Thread == KeGetCurrentThread() );
    00617
    00618     //
    00619     // Find the trap frame on the stack, so we can get the thread context
    00620     //
    00621     TrapFrame = (PKTRAP_FRAME)((PUCHAR)Thread->InitialStack -
    00622                 ALIGN_UP(sizeof(KTRAP_FRAME),KTRAP_FRAME_ALIGN) -
    00623                 sizeof(FX_SAVE_AREA));
    00624
    00625     ContextFrame.ContextFlags = CONTEXT_CONTROL;
    00626
    00627     KeContextFromKframes( TrapFrame,
    00628                           NULL,
    00629                           &ContextFrame );
    00630
    00631     //
    00632     // If AutoAlignment is TRUE, we want the processor to transparently fixup
    00633     // all alignment faults, so we clear the Alignment Check bit.  If
    00634     // AutoAlignment is FALSE, we set the bit, so 486 processors will
    00635     // give us alignment faults.
    00636     //
    00637
    00638     if (Thread->AutoAlignment) {
    00639         ContextFrame.EFlags &= (~EFLAGS_ALIGN_CHECK);
    00640     } else {
    00641         ContextFrame.EFlags |= EFLAGS_ALIGN_CHECK;
    00642     }
    00643
    00644     //
    00645     // Replace the modified EFlags in the trap frame.  When the thread returns
    00646     // to user mode, it will be running with the new alignment setting.
    00647     //
    00648
    00649     KeContextToKframes( TrapFrame,
    00650                         NULL,
    00651                         &ContextFrame,
    00652                         CONTEXT_CONTROL,
    00653                         KeGetPreviousMode() );
    00654
    00655     KeSetEvent(Event,0,FALSE);
    00656 }
    00657 #endif