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

intobj.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 intobj.c 00008 00009 Abstract: 00010 00011 This module implements the kernel interrupt object. Functions are provided 00012 to initialize, connect, and disconnect interrupt objects. 00013 00014 Author: 00015 00016 David N. Cutler (davec) 30-Jul-1989 00017 00018 Environment: 00019 00020 Kernel mode only. 00021 00022 Revision History: 00023 00024 23-Jan-1990 shielint 00025 00026 Modified for NT386 interrupt manager 00027 00028 --*/ 00029 00030 #include "ki.h" 00031 00032 // 00033 // Externs from trap.asm used to compute and set handlers for unexpected 00034 // hardware interrupts. 00035 // 00036 00037 extern ULONG KiStartUnexpectedRange(VOID); 00038 extern ULONG KiEndUnexpectedRange(VOID); 00039 extern ULONG KiUnexpectedEntrySize; 00040 00041 00042 VOID 00043 KiInterruptDispatch2ndLvl( 00044 VOID 00045 ); 00046 00047 00048 VOID 00049 KiChainedDispatch2ndLvl( 00050 VOID 00051 ); 00052 00053 00054 typedef enum { 00055 NoConnect, 00056 NormalConnect, 00057 ChainConnect, 00058 UnkownConnect 00059 } CONNECT_TYPE, *PCONNECT_TYPE; 00060 00061 typedef struct { 00062 CONNECT_TYPE Type; 00063 PKINTERRUPT Interrupt; 00064 PKINTERRUPT_ROUTINE NoDispatch; 00065 PKINTERRUPT_ROUTINE InterruptDispatch; 00066 PKINTERRUPT_ROUTINE FloatingDispatch; 00067 PKINTERRUPT_ROUTINE ChainedDispatch; 00068 PKINTERRUPT_ROUTINE *FlatDispatch; 00069 } DISPATCH_INFO, *PDISPATCH_INFO; 00070 00071 00072 VOID 00073 KiGetVectorInfo ( 00074 IN ULONG Vector, 00075 OUT PDISPATCH_INFO DispatchInfo 00076 ); 00077 00078 VOID 00079 KiConnectVectorAndInterruptObject ( 00080 IN PKINTERRUPT Interrupt, 00081 IN CONNECT_TYPE Type 00082 ); 00083 00084 00085 VOID 00086 KeInitializeInterrupt ( 00087 IN PKINTERRUPT Interrupt, 00088 IN PKSERVICE_ROUTINE ServiceRoutine, 00089 IN PVOID ServiceContext, 00090 IN PKSPIN_LOCK SpinLock OPTIONAL, 00091 IN ULONG Vector, 00092 IN KIRQL Irql, 00093 IN KIRQL SynchronizeIrql, 00094 IN KINTERRUPT_MODE InterruptMode, 00095 IN BOOLEAN ShareVector, 00096 IN CCHAR ProcessorNumber, 00097 IN BOOLEAN FloatingSave 00098 ) 00099 00100 /*++ 00101 00102 Routine Description: 00103 00104 This function initializes a kernel interrupt object. The service routine, 00105 service context, spin lock, vector, IRQL, SynchronizeIrql, and floating 00106 context save flag are initialized. 00107 00108 Arguments: 00109 00110 Interrupt - Supplies a pointer to a control object of type interrupt. 00111 00112 ServiceRoutine - Supplies a pointer to a function that is to be 00113 executed when an interrupt occurs via the specified interrupt 00114 vector. 00115 00116 ServiceContext - Supplies a pointer to an arbitrary data structure which is 00117 to be passed to the function specified by the ServiceRoutine parameter. 00118 00119 SpinLock - Supplies a pointer to an executive spin lock. 00120 00121 Vector - Supplies the index of the entry in the Interrupt Dispatch Table 00122 that is to be associated with the ServiceRoutine function. 00123 00124 Irql - Supplies the request priority of the interrupting source. 00125 00126 SynchronizeIrql - The request priority that the interrupt should be 00127 synchronized with. 00128 00129 InterruptMode - Supplies the mode of the interrupt; LevelSensitive or 00130 00131 ShareVector - Supplies a boolean value that specifies whether the 00132 vector can be shared with other interrupt objects or not. If FALSE 00133 then the vector may not be shared, if TRUE it may be. 00134 Latched. 00135 00136 ProcessorNumber - Supplies the number of the processor to which the 00137 interrupt will be connected. 00138 00139 FloatingSave - Supplies a boolean value that determines whether the 00140 floating point registers and pipe line are to be saved before calling 00141 the ServiceRoutine function. 00142 00143 Return Value: 00144 00145 None. 00146 00147 --*/ 00148 00149 { 00150 00151 LONG Index; 00152 PULONG pl; 00153 PULONG NormalDispatchCode; 00154 00155 // 00156 // Initialize standard control object header. 00157 // 00158 00159 Interrupt->Type = InterruptObject; 00160 Interrupt->Size = sizeof(KINTERRUPT); 00161 00162 // 00163 // Initialize the address of the service routine, 00164 // the service context, the address of the spin lock, the vector 00165 // number, the IRQL of the interrupting source, the Irql used for 00166 // synchronize execution, the interrupt mode, the processor 00167 // number, and the floating context save flag. 00168 // 00169 00170 Interrupt->ServiceRoutine = ServiceRoutine; 00171 Interrupt->ServiceContext = ServiceContext; 00172 00173 if (ARGUMENT_PRESENT(SpinLock)) { 00174 Interrupt->ActualLock = SpinLock; 00175 } else { 00176 KeInitializeSpinLock (&Interrupt->SpinLock); 00177 Interrupt->ActualLock = &Interrupt->SpinLock; 00178 } 00179 00180 Interrupt->Vector = Vector; 00181 Interrupt->Irql = Irql; 00182 Interrupt->SynchronizeIrql = SynchronizeIrql; 00183 Interrupt->Mode = InterruptMode; 00184 Interrupt->ShareVector = ShareVector; 00185 Interrupt->Number = ProcessorNumber; 00186 Interrupt->FloatingSave = FloatingSave; 00187 00188 // 00189 // Copy the interrupt dispatch code template into the interrupt object 00190 // and edit the machine code stored in the structure (please see 00191 // _KiInterruptTemplate in intsup.asm.) Finally, flush the dcache 00192 // on all processors that the current thread can 00193 // run on to ensure that the code is actually in memory. 00194 // 00195 00196 NormalDispatchCode = &(Interrupt->DispatchCode[0]); 00197 00198 pl = NormalDispatchCode; 00199 00200 for (Index = 0; Index < NORMAL_DISPATCH_LENGTH; Index += 1) { 00201 *NormalDispatchCode++ = KiInterruptTemplate[Index]; 00202 } 00203 00204 // 00205 // The following two instructions set the address of current interrupt 00206 // object the the NORMAL dispatching code. 00207 // 00208 00209 pl = (PULONG)((PUCHAR)pl + ((PUCHAR)&KiInterruptTemplateObject - 00210 (PUCHAR)KiInterruptTemplate) -4); 00211 *pl = (ULONG)Interrupt; 00212 00213 KeSweepDcache(FALSE); 00214 00215 // 00216 // Set the connected state of the interrupt object to FALSE. 00217 // 00218 00219 Interrupt->Connected = FALSE; 00220 return; 00221 } 00222 00223 BOOLEAN 00224 KeConnectInterrupt ( 00225 IN PKINTERRUPT Interrupt 00226 ) 00227 00228 /*++ 00229 00230 Routine Description: 00231 00232 This function connects an interrupt object to the interrupt vector 00233 specified by the interrupt object. If the interrupt object is already 00234 connected, or an attempt is made to connect to an interrupt that cannot 00235 be connected, then a value of FALSE is returned. Else the specified 00236 interrupt object is connected to the interrupt vector, the connected 00237 state is set to TRUE, and TRUE is returned as the function value. 00238 00239 Arguments: 00240 00241 Interrupt - Supplies a pointer to a control object of type interrupt. 00242 00243 Return Value: 00244 00245 If the interrupt object is already connected or an attempt is made to 00246 connect to an interrupt vector that cannot be connected, then a value 00247 of FALSE is returned. Else a value of TRUE is returned. 00248 00249 --*/ 00250 00251 { 00252 DISPATCH_INFO DispatchInfo; 00253 BOOLEAN Connected; 00254 BOOLEAN ConnectError; 00255 BOOLEAN Enabled; 00256 KIRQL Irql; 00257 CCHAR Number; 00258 KIRQL OldIrql; 00259 ULONG Vector; 00260 00261 // 00262 // If the interrupt object is already connected, the interrupt vector 00263 // number is invalid, an attempt is being made to connect to a vector 00264 // that cannot be connected, the interrupt request level is invalid, or 00265 // the processor number is invalid, then do not connect the interrupt 00266 // object. Else connect interrupt object to the specified vector and 00267 // establish the proper interrupt dispatcher. 00268 // 00269 00270 Connected = FALSE; 00271 ConnectError = FALSE; 00272 Irql = Interrupt->Irql; 00273 Number = Interrupt->Number; 00274 Vector = Interrupt->Vector; 00275 if ( !((Irql > HIGH_LEVEL) || 00276 (Number >= KeNumberProcessors) || 00277 (Interrupt->SynchronizeIrql < Irql) || 00278 (Interrupt->FloatingSave) // R0 x87 usage not supported on x86 00279 ) 00280 ) { 00281 00282 // 00283 // 00284 // Set system affinity to the specified processor. 00285 // 00286 00287 KeSetSystemAffinityThread((KAFFINITY)(1<<Number)); 00288 00289 // 00290 // Raise IRQL to dispatcher level and lock dispatcher database. 00291 // 00292 00293 KiLockDispatcherDatabase(&OldIrql); 00294 00295 // 00296 // Is interrupt object already connected? 00297 // 00298 00299 if (!Interrupt->Connected) { 00300 00301 // 00302 // Determine interrupt dispatch vector 00303 // 00304 00305 KiGetVectorInfo ( 00306 Vector, 00307 &DispatchInfo 00308 ); 00309 00310 // 00311 // If dispatch vector is not connected, then connect it 00312 // 00313 00314 if (DispatchInfo.Type == NoConnect) { 00315 Connected = TRUE; 00316 Interrupt->Connected = TRUE; 00317 00318 // 00319 // Connect interrupt dispatch to interrupt object dispatch code 00320 // 00321 00322 InitializeListHead(&Interrupt->InterruptListEntry); 00323 KiConnectVectorAndInterruptObject (Interrupt, NormalConnect); 00324 00325 // 00326 // Enabled system vector 00327 // 00328 00329 Enabled = HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode); 00330 if (!Enabled) { 00331 ConnectError = TRUE; 00332 } 00333 00334 00335 } else if (DispatchInfo.Type != UnkownConnect && 00336 Interrupt->ShareVector && 00337 DispatchInfo.Interrupt->ShareVector && 00338 DispatchInfo.Interrupt->Mode == Interrupt->Mode) { 00339 00340 // 00341 // Vector is already connected as sharable. New vector is sharable 00342 // and modes match. Chain new vector. 00343 // 00344 00345 Connected = TRUE; 00346 Interrupt->Connected = TRUE; 00347 00348 ASSERT (Irql <= SYNCH_LEVEL); 00349 00350 // 00351 // If not already using chained dispatch handler, set it up 00352 // 00353 00354 if (DispatchInfo.Type != ChainConnect) { 00355 KiConnectVectorAndInterruptObject (DispatchInfo.Interrupt, ChainConnect); 00356 } 00357 00358 // 00359 // Add to tail of chained dispatch 00360 // 00361 00362 InsertTailList( 00363 &DispatchInfo.Interrupt->InterruptListEntry, 00364 &Interrupt->InterruptListEntry 00365 ); 00366 00367 } 00368 } 00369 00370 // 00371 // Unlock dispatcher database and lower IRQL to its previous value. 00372 // 00373 00374 KiUnlockDispatcherDatabase(OldIrql); 00375 00376 // 00377 // Set system affinity back to the original value. 00378 // 00379 00380 KeRevertToUserAffinityThread(); 00381 } 00382 00383 if (Connected && ConnectError) { 00384 #if DBG 00385 DbgPrint ("HalEnableSystemInterrupt failed\n"); 00386 #endif 00387 KeDisconnectInterrupt (Interrupt); 00388 Connected = FALSE; 00389 } 00390 00391 // 00392 // Return whether interrupt was connected to the specified vector. 00393 // 00394 00395 return Connected; 00396 } 00397 00398 BOOLEAN 00399 KeDisconnectInterrupt ( 00400 IN PKINTERRUPT Interrupt 00401 ) 00402 00403 /*++ 00404 00405 Routine Description: 00406 00407 This function disconnects an interrupt object from the interrupt vector 00408 specified by the interrupt object. If the interrupt object is not 00409 connected, then a value of FALSE is returned. Else the specified interrupt 00410 object is disconnected from the interrupt vector, the connected state is 00411 set to FALSE, and TRUE is returned as the function value. 00412 00413 Arguments: 00414 00415 Interrupt - Supplies a pointer to a control object of type interrupt. 00416 00417 Return Value: 00418 00419 If the interrupt object is not connected, then a value of FALSE is 00420 returned. Else a value of TRUE is returned. 00421 00422 --*/ 00423 00424 { 00425 00426 DISPATCH_INFO DispatchInfo; 00427 BOOLEAN Connected; 00428 PKINTERRUPT Interrupty; 00429 KIRQL Irql; 00430 KIRQL OldIrql; 00431 ULONG Vector; 00432 00433 // 00434 // Set system affinity to the specified processor. 00435 // 00436 00437 KeSetSystemAffinityThread((KAFFINITY)(1<<Interrupt->Number)); 00438 00439 // 00440 // Raise IRQL to dispatcher level and lock dispatcher database. 00441 // 00442 00443 KiLockDispatcherDatabase(&OldIrql); 00444 00445 // 00446 // If the interrupt object is connected, then disconnect it from the 00447 // specified vector. 00448 // 00449 00450 Connected = Interrupt->Connected; 00451 if (Connected) { 00452 Irql = Interrupt->Irql; 00453 Vector = Interrupt->Vector; 00454 00455 // 00456 // If the specified interrupt vector is not connected to the chained 00457 // interrupt dispatcher, then disconnect it by setting its dispatch 00458 // address to the unexpected interrupt routine. Else remove the 00459 // interrupt object from the interrupt chain. If there is only 00460 // one entry remaining in the list, then reestablish the dispatch 00461 // address. 00462 // 00463 00464 // 00465 // Determine interrupt dispatch vector 00466 // 00467 00468 KiGetVectorInfo ( 00469 Vector, 00470 &DispatchInfo 00471 ); 00472 00473 00474 // 00475 // Is dispatch a chained handler? 00476 // 00477 00478 if (DispatchInfo.Type == ChainConnect) { 00479 00480 ASSERT (Irql <= SYNCH_LEVEL); 00481 00482 // 00483 // Is interrupt being removed from head? 00484 // 00485 00486 if (Interrupt == DispatchInfo.Interrupt) { 00487 00488 // 00489 // Update next interrupt object to be head 00490 // 00491 00492 DispatchInfo.Interrupt = CONTAINING_RECORD( 00493 DispatchInfo.Interrupt->InterruptListEntry.Flink, 00494 KINTERRUPT, 00495 InterruptListEntry 00496 ); 00497 00498 KiConnectVectorAndInterruptObject (DispatchInfo.Interrupt, ChainConnect); 00499 } 00500 00501 // 00502 // Remove interrupt object 00503 // 00504 00505 RemoveEntryList(&Interrupt->InterruptListEntry); 00506 00507 // 00508 // If there's only one interrupt object left on this vector, 00509 // determine proper interrupt dispatcher 00510 // 00511 00512 Interrupty = CONTAINING_RECORD( 00513 DispatchInfo.Interrupt->InterruptListEntry.Flink, 00514 KINTERRUPT, 00515 InterruptListEntry 00516 ); 00517 00518 if (DispatchInfo.Interrupt == Interrupty) { 00519 KiConnectVectorAndInterruptObject (Interrupty, NormalConnect); 00520 } 00521 00522 } else { 00523 00524 // 00525 // Removing last interrupt object from the vector. Disable the 00526 // vector, and set it to unconnected 00527 // 00528 00529 HalDisableSystemInterrupt(Interrupt->Vector, Irql); 00530 KiConnectVectorAndInterruptObject (Interrupt, NoConnect); 00531 } 00532 00533 00534 KeSweepIcache(TRUE); 00535 Interrupt->Connected = FALSE; 00536 } 00537 00538 // 00539 // Unlock dispatcher database and lower IRQL to its previous value. 00540 // 00541 00542 KiUnlockDispatcherDatabase(OldIrql); 00543 00544 // 00545 // Set system affinity back to the original value. 00546 // 00547 00548 KeRevertToUserAffinityThread(); 00549 00550 // 00551 // Return whether interrupt was disconnected from the specified vector. 00552 // 00553 00554 return Connected; 00555 } 00556 00557 VOID 00558 KiGetVectorInfo ( 00559 IN ULONG Vector, 00560 OUT PDISPATCH_INFO DispatchInfo 00561 ) 00562 { 00563 PKINTERRUPT_ROUTINE Dispatch; 00564 ULONG CurrentDispatch; 00565 ULONG DispatchType; 00566 00567 // 00568 // Get second level dispatch point 00569 // 00570 00571 00572 DispatchType = HalSystemVectorDispatchEntry ( 00573 Vector, 00574 &DispatchInfo->FlatDispatch, 00575 &DispatchInfo->NoDispatch 00576 ); 00577 00578 // 00579 // Get vector info 00580 // 00581 00582 switch (DispatchType) { 00583 case 0: 00584 // 00585 // Primary dispatch 00586 // 00587 00588 DispatchInfo->NoDispatch = (PKINTERRUPT_ROUTINE) (((ULONG) &KiStartUnexpectedRange) + 00589 (Vector - PRIMARY_VECTOR_BASE) * KiUnexpectedEntrySize); 00590 00591 DispatchInfo->InterruptDispatch = KiInterruptDispatch; 00592 DispatchInfo->FloatingDispatch = KiFloatingDispatch; 00593 DispatchInfo->ChainedDispatch = KiChainedDispatch; 00594 DispatchInfo->FlatDispatch = NULL; 00595 00596 CurrentDispatch = (ULONG) KiReturnHandlerAddressFromIDT(Vector); 00597 DispatchInfo->Interrupt = CONTAINING_RECORD ( 00598 CurrentDispatch, 00599 KINTERRUPT, 00600 DispatchCode 00601 ); 00602 break; 00603 00604 case 1: 00605 // 00606 // Secondardy dispatch. 00607 // 00608 00609 DispatchInfo->InterruptDispatch = KiInterruptDispatch2ndLvl; 00610 DispatchInfo->FloatingDispatch = KiInterruptDispatch2ndLvl; 00611 DispatchInfo->ChainedDispatch = KiChainedDispatch2ndLvl; 00612 00613 CurrentDispatch = (ULONG) *DispatchInfo->FlatDispatch; 00614 DispatchInfo->Interrupt = (PKINTERRUPT) ( (PUCHAR) CurrentDispatch - 00615 (PUCHAR) KiInterruptTemplate + 00616 (PUCHAR) &KiInterruptTemplate2ndDispatch 00617 ); 00618 break; 00619 00620 default: 00621 // Other values reserved 00622 KeBugCheck (MISMATCHED_HAL); 00623 } 00624 00625 00626 // 00627 // Determine dispatch type 00628 // 00629 00630 if (((PKINTERRUPT_ROUTINE) CurrentDispatch) == DispatchInfo->NoDispatch) { 00631 00632 // 00633 // Is connected to the NoDispatch function 00634 // 00635 00636 DispatchInfo->Type = NoConnect; 00637 00638 } else { 00639 Dispatch = DispatchInfo->Interrupt->DispatchAddress; 00640 00641 if (Dispatch == DispatchInfo->ChainedDispatch) { 00642 // 00643 // Is connected to the chained handler 00644 // 00645 00646 DispatchInfo->Type = ChainConnect; 00647 00648 } else if (Dispatch == DispatchInfo->InterruptDispatch || 00649 Dispatch == DispatchInfo->FloatingDispatch) { 00650 // 00651 // If connection to the non-chained handler 00652 // 00653 00654 DispatchInfo->Type = NormalConnect; 00655 00656 } else { 00657 00658 // 00659 // Unkown connection 00660 // 00661 00662 DispatchInfo->Type = UnkownConnect; 00663 #if DBG 00664 DbgPrint ("KiGetVectorInfo not understood\n"); 00665 #endif 00666 } 00667 } 00668 } 00669 00670 VOID 00671 KiConnectVectorAndInterruptObject ( 00672 IN PKINTERRUPT Interrupt, 00673 IN CONNECT_TYPE Type 00674 ) 00675 { 00676 PKINTERRUPT_ROUTINE DispatchAddress; 00677 DISPATCH_INFO DispatchInfo; 00678 PULONG pl; 00679 00680 // 00681 // Get current connect info 00682 // 00683 00684 KiGetVectorInfo ( 00685 Interrupt->Vector, 00686 &DispatchInfo 00687 ); 00688 00689 // 00690 // If disconnecting, set vector to NoDispatch 00691 // 00692 00693 if (Type == NoConnect) { 00694 00695 DispatchAddress = DispatchInfo.NoDispatch; 00696 00697 } else { 00698 00699 // 00700 // Set interrupt objects dispatch for new type 00701 // 00702 00703 DispatchAddress = DispatchInfo.ChainedDispatch; 00704 00705 if (Type == NormalConnect) { 00706 DispatchAddress = DispatchInfo.InterruptDispatch; 00707 if (Interrupt->FloatingSave) { 00708 DispatchAddress = DispatchInfo.FloatingDispatch; 00709 } 00710 } 00711 00712 Interrupt->DispatchAddress = DispatchAddress; 00713 00714 // 00715 // Set interrupt objects dispatch code to kernel dispatcher 00716 // 00717 00718 pl = &(Interrupt->DispatchCode[0]); 00719 pl = (PULONG)((PUCHAR)pl + 00720 ((PUCHAR)&KiInterruptTemplateDispatch - 00721 (PUCHAR)KiInterruptTemplate) -4); 00722 00723 *pl = (ULONG)DispatchAddress-(ULONG)((PUCHAR)pl+4); 00724 00725 // 00726 // Set dispatch vector to proper address dispatch code location 00727 // 00728 00729 if (DispatchInfo.FlatDispatch) { 00730 00731 // 00732 // Connect to flat dispatch 00733 // 00734 00735 DispatchAddress = (PKINTERRUPT_ROUTINE) 00736 ((PUCHAR) &(Interrupt->DispatchCode[0]) + 00737 ((PUCHAR) &KiInterruptTemplate2ndDispatch - 00738 (PUCHAR) KiInterruptTemplate)); 00739 00740 } else { 00741 00742 // 00743 // Connect to enter_all dispatch 00744 // 00745 00746 DispatchAddress = (PKINTERRUPT_ROUTINE) &Interrupt->DispatchCode; 00747 } 00748 } 00749 00750 00751 if (DispatchInfo.FlatDispatch) { 00752 00753 // 00754 // Connect to flat dispatch 00755 // 00756 00757 *DispatchInfo.FlatDispatch = DispatchAddress; 00758 00759 } else { 00760 00761 // 00762 // Connect to IDT 00763 // 00764 00765 KiSetHandlerAddressToIDT (Interrupt->Vector, DispatchAddress); 00766 } 00767 }

Generated on Sat May 15 19:40:28 2004 for test by doxygen 1.3.7