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

Generated on Sat May 15 19:41:58 2004 for test by doxygen 1.3.7