Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenirqobj.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ke/i386/irq.c 00005 * PURPOSE: Manages the Kernel's IRQ support for external drivers, 00006 * for the purposes of connecting, disconnecting and setting 00007 * up ISRs for drivers. The backend behind the Io* Interrupt 00008 * routines. 00009 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00010 */ 00011 00012 /* INCLUDES *****************************************************************/ 00013 00014 #include <ntoskrnl.h> 00015 #define NDEBUG 00016 #include <debug.h> 00017 00018 /* GLOBALS *******************************************************************/ 00019 00020 ULONG KiISRTimeout = 55; 00021 USHORT KiISROverflow = 30000; 00022 extern ULONG NTAPI KiChainedDispatch2ndLvl(VOID); 00023 00024 /* PRIVATE FUNCTIONS *********************************************************/ 00025 00026 VOID 00027 NTAPI 00028 KiGetVectorDispatch(IN ULONG Vector, 00029 IN PDISPATCH_INFO Dispatch) 00030 { 00031 PKINTERRUPT_ROUTINE Handler; 00032 PVOID Current; 00033 UCHAR Type; 00034 UCHAR Entry; 00035 00036 /* Check if this is a primary or 2nd-level dispatch */ 00037 Type = HalSystemVectorDispatchEntry(Vector, 00038 &Dispatch->FlatDispatch, 00039 &Dispatch->NoDispatch); 00040 ASSERT(Type == 0); 00041 00042 /* Get the IDT entry for this vector */ 00043 Entry = HalVectorToIDTEntry(Vector); 00044 00045 /* Setup the unhandled dispatch */ 00046 Dispatch->NoDispatch = (PVOID)(((ULONG_PTR)&KiStartUnexpectedRange) + 00047 (Entry - PRIMARY_VECTOR_BASE) * 00048 KiUnexpectedEntrySize); 00049 00050 /* Setup the handlers */ 00051 Dispatch->InterruptDispatch = (PVOID)KiInterruptDispatch; 00052 Dispatch->FloatingDispatch = NULL; // Floating Interrupts are not supported 00053 Dispatch->ChainedDispatch = (PVOID)KiChainedDispatch; 00054 Dispatch->FlatDispatch = NULL; 00055 00056 /* Get the current handler */ 00057 Current = KeQueryInterruptHandler(Vector); 00058 00059 /* Set the interrupt */ 00060 Dispatch->Interrupt = CONTAINING_RECORD(Current, 00061 KINTERRUPT, 00062 DispatchCode); 00063 00064 /* Check what this interrupt is connected to */ 00065 if ((PKINTERRUPT_ROUTINE)Current == Dispatch->NoDispatch) 00066 { 00067 /* Not connected */ 00068 Dispatch->Type = NoConnect; 00069 } 00070 else 00071 { 00072 /* Get the handler */ 00073 Handler = Dispatch->Interrupt->DispatchAddress; 00074 if (Handler == Dispatch->ChainedDispatch) 00075 { 00076 /* It's a chained interrupt */ 00077 Dispatch->Type = ChainConnect; 00078 } 00079 else if ((Handler == Dispatch->InterruptDispatch) || 00080 (Handler == Dispatch->FloatingDispatch)) 00081 { 00082 /* It's unchained */ 00083 Dispatch->Type = NormalConnect; 00084 } 00085 else 00086 { 00087 /* Unknown */ 00088 Dispatch->Type = UnknownConnect; 00089 } 00090 } 00091 } 00092 00093 VOID 00094 NTAPI 00095 KiConnectVectorToInterrupt(IN PKINTERRUPT Interrupt, 00096 IN CONNECT_TYPE Type) 00097 { 00098 DISPATCH_INFO Dispatch; 00099 PKINTERRUPT_ROUTINE Handler; 00100 00101 /* Get vector data */ 00102 KiGetVectorDispatch(Interrupt->Vector, &Dispatch); 00103 00104 /* Check if we're only disconnecting */ 00105 if (Type == NoConnect) 00106 { 00107 /* Set the handler to NoDispatch */ 00108 Handler = Dispatch.NoDispatch; 00109 } 00110 else 00111 { 00112 /* Get the right handler */ 00113 Handler = (Type == NormalConnect) ? 00114 Dispatch.InterruptDispatch: 00115 Dispatch.ChainedDispatch; 00116 ASSERT(Interrupt->FloatingSave == FALSE); 00117 00118 /* Set the handler */ 00119 Interrupt->DispatchAddress = Handler; 00120 00121 /* Read note in trap.s -- patching not needed since JMP is static */ 00122 00123 /* Now set the final handler address */ 00124 ASSERT(Dispatch.FlatDispatch == NULL); 00125 Handler = (PVOID)&Interrupt->DispatchCode; 00126 } 00127 00128 /* Register the interrupt */ 00129 KeRegisterInterruptHandler(Interrupt->Vector, Handler); 00130 } 00131 00132 VOID 00133 FORCEINLINE 00134 DECLSPEC_NORETURN 00135 KiExitInterrupt(IN PKTRAP_FRAME TrapFrame, 00136 IN KIRQL OldIrql, 00137 IN BOOLEAN Spurious) 00138 { 00139 /* Check if this was a real interrupt */ 00140 if (!Spurious) 00141 { 00142 /* It was, disable interrupts and restore the IRQL */ 00143 _disable(); 00144 HalEndSystemInterrupt(OldIrql, TrapFrame); 00145 } 00146 00147 /* Now exit the trap */ 00148 KiEoiHelper(TrapFrame); 00149 } 00150 00151 VOID 00152 KiUnexpectedInterrupt(VOID) 00153 { 00154 /* Crash the machine */ 00155 KeBugCheck(TRAP_CAUSE_UNKNOWN); 00156 } 00157 00158 VOID 00159 FASTCALL 00160 KiUnexpectedInterruptTailHandler(IN PKTRAP_FRAME TrapFrame) 00161 { 00162 KIRQL OldIrql; 00163 00164 /* Enter trap */ 00165 KiEnterInterruptTrap(TrapFrame); 00166 00167 /* Increase interrupt count */ 00168 KeGetCurrentPrcb()->InterruptCount++; 00169 00170 /* Start the interrupt */ 00171 if (HalBeginSystemInterrupt(HIGH_LEVEL, TrapFrame->ErrCode, &OldIrql)) 00172 { 00173 /* Warn user */ 00174 DPRINT1("\n\x7\x7!!! Unexpected Interrupt 0x%02lx !!!\n", TrapFrame->ErrCode); 00175 00176 /* Now call the epilogue code */ 00177 KiExitInterrupt(TrapFrame, OldIrql, FALSE); 00178 } 00179 else 00180 { 00181 /* Now call the epilogue code */ 00182 KiExitInterrupt(TrapFrame, OldIrql, TRUE); 00183 } 00184 } 00185 00186 typedef 00187 VOID 00188 (FASTCALL *PKI_INTERRUPT_DISPATCH)( 00189 IN PKTRAP_FRAME TrapFrame, 00190 IN PKINTERRUPT Interrupt 00191 ); 00192 00193 VOID 00194 FASTCALL 00195 KiInterruptDispatch(IN PKTRAP_FRAME TrapFrame, 00196 IN PKINTERRUPT Interrupt) 00197 { 00198 KIRQL OldIrql; 00199 00200 /* Increase interrupt count */ 00201 KeGetCurrentPrcb()->InterruptCount++; 00202 00203 /* Begin the interrupt, making sure it's not spurious */ 00204 if (HalBeginSystemInterrupt(Interrupt->SynchronizeIrql, 00205 Interrupt->Vector, 00206 &OldIrql)) 00207 { 00208 /* Acquire interrupt lock */ 00209 KxAcquireSpinLock(Interrupt->ActualLock); 00210 00211 /* Call the ISR */ 00212 Interrupt->ServiceRoutine(Interrupt, Interrupt->ServiceContext); 00213 00214 /* Release interrupt lock */ 00215 KxReleaseSpinLock(Interrupt->ActualLock); 00216 00217 /* Now call the epilogue code */ 00218 KiExitInterrupt(TrapFrame, OldIrql, FALSE); 00219 } 00220 else 00221 { 00222 /* Now call the epilogue code */ 00223 KiExitInterrupt(TrapFrame, OldIrql, TRUE); 00224 } 00225 } 00226 00227 VOID 00228 FASTCALL 00229 KiChainedDispatch(IN PKTRAP_FRAME TrapFrame, 00230 IN PKINTERRUPT Interrupt) 00231 { 00232 KIRQL OldIrql; 00233 BOOLEAN Handled; 00234 PLIST_ENTRY NextEntry, ListHead; 00235 00236 /* Increase interrupt count */ 00237 KeGetCurrentPrcb()->InterruptCount++; 00238 00239 /* Begin the interrupt, making sure it's not spurious */ 00240 if (HalBeginSystemInterrupt(Interrupt->Irql, 00241 Interrupt->Vector, 00242 &OldIrql)) 00243 { 00244 /* Get list pointers */ 00245 ListHead = &Interrupt->InterruptListEntry; 00246 NextEntry = ListHead; /* The head is an entry! */ 00247 while (TRUE) 00248 { 00249 /* Check if this interrupt's IRQL is higher than the current one */ 00250 if (Interrupt->SynchronizeIrql > Interrupt->Irql) 00251 { 00252 /* Raise to higher IRQL */ 00253 OldIrql = KfRaiseIrql(Interrupt->SynchronizeIrql); 00254 } 00255 00256 /* Acquire interrupt lock */ 00257 KxAcquireSpinLock(Interrupt->ActualLock); 00258 00259 /* Call the ISR */ 00260 Handled = Interrupt->ServiceRoutine(Interrupt, 00261 Interrupt->ServiceContext); 00262 00263 /* Release interrupt lock */ 00264 KxReleaseSpinLock(Interrupt->ActualLock); 00265 00266 /* Check if this interrupt's IRQL is higher than the current one */ 00267 if (Interrupt->SynchronizeIrql > Interrupt->Irql) 00268 { 00269 /* Lower the IRQL back */ 00270 KfLowerIrql(OldIrql); 00271 } 00272 00273 /* Check if the interrupt got handled and it's level */ 00274 if ((Handled) && (Interrupt->Mode == LevelSensitive)) break; 00275 00276 /* What's next? */ 00277 NextEntry = NextEntry->Flink; 00278 00279 /* Is this the last one? */ 00280 if (NextEntry == ListHead) 00281 { 00282 /* Level should not have gotten here */ 00283 if (Interrupt->Mode == LevelSensitive) break; 00284 00285 /* As for edge, we can only exit once nobody can handle the interrupt */ 00286 if (!Handled) break; 00287 } 00288 00289 /* Get the interrupt object for the next pass */ 00290 Interrupt = CONTAINING_RECORD(NextEntry, KINTERRUPT, InterruptListEntry); 00291 } 00292 00293 /* Now call the epilogue code */ 00294 KiExitInterrupt(TrapFrame, OldIrql, FALSE); 00295 } 00296 else 00297 { 00298 /* Now call the epilogue code */ 00299 KiExitInterrupt(TrapFrame, OldIrql, TRUE); 00300 } 00301 } 00302 00303 VOID 00304 FASTCALL 00305 KiInterruptTemplateHandler(IN PKTRAP_FRAME TrapFrame, 00306 IN PKINTERRUPT Interrupt) 00307 { 00308 /* Enter interrupt frame */ 00309 KiEnterInterruptTrap(TrapFrame); 00310 00311 /* Call the correct dispatcher */ 00312 ((PKI_INTERRUPT_DISPATCH)Interrupt->DispatchAddress)(TrapFrame, Interrupt); 00313 } 00314 00315 00316 /* PUBLIC FUNCTIONS **********************************************************/ 00317 00318 /* 00319 * @implemented 00320 */ 00321 VOID 00322 NTAPI 00323 KeInitializeInterrupt(IN PKINTERRUPT Interrupt, 00324 IN PKSERVICE_ROUTINE ServiceRoutine, 00325 IN PVOID ServiceContext, 00326 IN PKSPIN_LOCK SpinLock, 00327 IN ULONG Vector, 00328 IN KIRQL Irql, 00329 IN KIRQL SynchronizeIrql, 00330 IN KINTERRUPT_MODE InterruptMode, 00331 IN BOOLEAN ShareVector, 00332 IN CHAR ProcessorNumber, 00333 IN BOOLEAN FloatingSave) 00334 { 00335 ULONG i; 00336 PULONG DispatchCode = &Interrupt->DispatchCode[0], Patch = DispatchCode; 00337 00338 /* Set the Interrupt Header */ 00339 Interrupt->Type = InterruptObject; 00340 Interrupt->Size = sizeof(KINTERRUPT); 00341 00342 /* Check if we got a spinlock */ 00343 if (SpinLock) 00344 { 00345 Interrupt->ActualLock = SpinLock; 00346 } 00347 else 00348 { 00349 /* This means we'll be usin the built-in one */ 00350 KeInitializeSpinLock(&Interrupt->SpinLock); 00351 Interrupt->ActualLock = &Interrupt->SpinLock; 00352 } 00353 00354 /* Set the other settings */ 00355 Interrupt->ServiceRoutine = ServiceRoutine; 00356 Interrupt->ServiceContext = ServiceContext; 00357 Interrupt->Vector = Vector; 00358 Interrupt->Irql = Irql; 00359 Interrupt->SynchronizeIrql = SynchronizeIrql; 00360 Interrupt->Mode = InterruptMode; 00361 Interrupt->ShareVector = ShareVector; 00362 Interrupt->Number = ProcessorNumber; 00363 Interrupt->FloatingSave = FloatingSave; 00364 Interrupt->TickCount = MAXULONG; 00365 Interrupt->DispatchCount = MAXULONG; 00366 00367 /* Loop the template in memory */ 00368 for (i = 0; i < DISPATCH_LENGTH; i++) 00369 { 00370 /* Copy the dispatch code */ 00371 *DispatchCode++ = ((PULONG)KiInterruptTemplate)[i]; 00372 } 00373 00374 /* Jump to the last 4 bytes */ 00375 Patch = (PULONG)((ULONG_PTR)Patch + 00376 ((ULONG_PTR)&KiInterruptTemplateObject - 00377 (ULONG_PTR)KiInterruptTemplate) - 4); 00378 00379 /* Apply the patch */ 00380 *Patch = PtrToUlong(Interrupt); 00381 00382 /* Disconnect it at first */ 00383 Interrupt->Connected = FALSE; 00384 } 00385 00386 /* 00387 * @implemented 00388 */ 00389 BOOLEAN 00390 NTAPI 00391 KeConnectInterrupt(IN PKINTERRUPT Interrupt) 00392 { 00393 BOOLEAN Connected, Error, Status; 00394 KIRQL Irql, OldIrql; 00395 UCHAR Number; 00396 ULONG Vector; 00397 DISPATCH_INFO Dispatch; 00398 00399 /* Get data from interrupt */ 00400 Number = Interrupt->Number; 00401 Vector = Interrupt->Vector; 00402 Irql = Interrupt->Irql; 00403 00404 /* Validate the settings */ 00405 if ((Irql > HIGH_LEVEL) || 00406 (Number >= KeNumberProcessors) || 00407 (Interrupt->SynchronizeIrql < Irql) || 00408 (Interrupt->FloatingSave)) 00409 { 00410 return FALSE; 00411 } 00412 00413 /* Set defaults */ 00414 Connected = FALSE; 00415 Error = FALSE; 00416 00417 /* Set the system affinity and acquire the dispatcher lock */ 00418 KeSetSystemAffinityThread(1 << Number); 00419 OldIrql = KiAcquireDispatcherLock(); 00420 00421 /* Check if it's already been connected */ 00422 if (!Interrupt->Connected) 00423 { 00424 /* Get vector dispatching information */ 00425 KiGetVectorDispatch(Vector, &Dispatch); 00426 00427 /* Check if the vector is already connected */ 00428 if (Dispatch.Type == NoConnect) 00429 { 00430 /* Do the connection */ 00431 Interrupt->Connected = Connected = TRUE; 00432 00433 /* Initialize the list */ 00434 InitializeListHead(&Interrupt->InterruptListEntry); 00435 00436 /* Connect and enable the interrupt */ 00437 KiConnectVectorToInterrupt(Interrupt, NormalConnect); 00438 Status = HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode); 00439 if (!Status) Error = TRUE; 00440 } 00441 else if ((Dispatch.Type != UnknownConnect) && 00442 (Interrupt->ShareVector) && 00443 (Dispatch.Interrupt->ShareVector) && 00444 (Dispatch.Interrupt->Mode == Interrupt->Mode)) 00445 { 00446 /* The vector is shared and the interrupts are compatible */ 00447 Interrupt->Connected = Connected = TRUE; 00448 00449 /* FIXME */ 00450 // ASSERT(Irql <= SYNCH_LEVEL); 00451 00452 /* Check if this is the first chain */ 00453 if (Dispatch.Type != ChainConnect) 00454 { 00455 /* This is not supported */ 00456 ASSERT(Dispatch.Interrupt->Mode != Latched); 00457 00458 /* Setup the chainned handler */ 00459 KiConnectVectorToInterrupt(Dispatch.Interrupt, ChainConnect); 00460 } 00461 00462 /* Insert into the interrupt list */ 00463 InsertTailList(&Dispatch.Interrupt->InterruptListEntry, 00464 &Interrupt->InterruptListEntry); 00465 } 00466 } 00467 00468 /* Unlock the dispatcher and revert affinity */ 00469 KiReleaseDispatcherLock(OldIrql); 00470 KeRevertToUserAffinityThread(); 00471 00472 /* Check if we failed while trying to connect */ 00473 if ((Connected) && (Error)) 00474 { 00475 DPRINT1("HalEnableSystemInterrupt failed\n"); 00476 KeDisconnectInterrupt(Interrupt); 00477 Connected = FALSE; 00478 } 00479 00480 /* Return to caller */ 00481 return Connected; 00482 } 00483 00484 /* 00485 * @implemented 00486 */ 00487 BOOLEAN 00488 NTAPI 00489 KeDisconnectInterrupt(IN PKINTERRUPT Interrupt) 00490 { 00491 KIRQL OldIrql, Irql; 00492 ULONG Vector; 00493 DISPATCH_INFO Dispatch; 00494 PKINTERRUPT NextInterrupt; 00495 BOOLEAN State; 00496 00497 /* Set the affinity */ 00498 KeSetSystemAffinityThread(1 << Interrupt->Number); 00499 00500 /* Lock the dispatcher */ 00501 OldIrql = KiAcquireDispatcherLock(); 00502 00503 /* Check if it's actually connected */ 00504 State = Interrupt->Connected; 00505 if (State) 00506 { 00507 /* Get the vector and IRQL */ 00508 Irql = Interrupt->Irql; 00509 Vector = Interrupt->Vector; 00510 00511 /* Get vector dispatch data */ 00512 KiGetVectorDispatch(Vector, &Dispatch); 00513 00514 /* Check if it was chained */ 00515 if (Dispatch.Type == ChainConnect) 00516 { 00517 /* Check if the top-level interrupt is being removed */ 00518 ASSERT(Irql <= SYNCH_LEVEL); 00519 if (Interrupt == Dispatch.Interrupt) 00520 { 00521 /* Get the next one */ 00522 Dispatch.Interrupt = CONTAINING_RECORD(Dispatch.Interrupt-> 00523 InterruptListEntry.Flink, 00524 KINTERRUPT, 00525 InterruptListEntry); 00526 00527 /* Reconnect it */ 00528 KiConnectVectorToInterrupt(Dispatch.Interrupt, ChainConnect); 00529 } 00530 00531 /* Remove it */ 00532 RemoveEntryList(&Interrupt->InterruptListEntry); 00533 00534 /* Get the next one */ 00535 NextInterrupt = CONTAINING_RECORD(Dispatch.Interrupt-> 00536 InterruptListEntry.Flink, 00537 KINTERRUPT, 00538 InterruptListEntry); 00539 00540 /* Check if this is the only one left */ 00541 if (Dispatch.Interrupt == NextInterrupt) 00542 { 00543 /* Connect it in non-chained mode */ 00544 KiConnectVectorToInterrupt(Dispatch.Interrupt, NormalConnect); 00545 } 00546 } 00547 else 00548 { 00549 /* Only one left, disable and remove it */ 00550 HalDisableSystemInterrupt(Interrupt->Vector, Irql); 00551 KiConnectVectorToInterrupt(Interrupt, NoConnect); 00552 } 00553 00554 /* Disconnect it */ 00555 Interrupt->Connected = FALSE; 00556 } 00557 00558 /* Unlock the dispatcher and revert affinity */ 00559 KiReleaseDispatcherLock(OldIrql); 00560 KeRevertToUserAffinityThread(); 00561 00562 /* Return to caller */ 00563 return State; 00564 } 00565 00566 /* 00567 * @implemented 00568 */ 00569 BOOLEAN 00570 NTAPI 00571 KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt, 00572 IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine, 00573 IN PVOID SynchronizeContext OPTIONAL) 00574 { 00575 BOOLEAN Success; 00576 KIRQL OldIrql; 00577 00578 /* Raise IRQL */ 00579 OldIrql = KfRaiseIrql(Interrupt->SynchronizeIrql); 00580 00581 /* Acquire interrupt spinlock */ 00582 KeAcquireSpinLockAtDpcLevel(Interrupt->ActualLock); 00583 00584 /* Call the routine */ 00585 Success = SynchronizeRoutine(SynchronizeContext); 00586 00587 /* Release lock */ 00588 KeReleaseSpinLockFromDpcLevel(Interrupt->ActualLock); 00589 00590 /* Lower IRQL */ 00591 KfLowerIrql(OldIrql); 00592 00593 /* Return status */ 00594 return Success; 00595 } 00596 00597 /* EOF */ Generated on Thu May 24 2012 04:37:53 for ReactOS by
1.7.6.1
|