ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

irqobj.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.