test: intobj.c Source File

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) 1990  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     Peter L. Johnston (plj@vnet.ibm.com) 5-Oct-1993
    00017     Based on original code by David N. Cutler (davec) 3-Apr-1990
    00018
    00019 Environment:
    00020
    00021     Kernel mode only.
    00022
    00023 Revision History:
    00024
    00025     29-Jun-94    plj    Updated for Daytona. (post Beta 2)
    00026
    00027 --*/
    00028
    00029 #include "ki.h"
    00030
    00031
    00032 VOID
    00033 KeInitializeInterrupt (
    00034     IN PKINTERRUPT Interrupt,
    00035     IN PKSERVICE_ROUTINE ServiceRoutine,
    00036     IN PVOID ServiceContext,
    00037     IN PKSPIN_LOCK SpinLock OPTIONAL,
    00038     IN ULONG Vector,
    00039     IN KIRQL Irql,
    00040     IN KIRQL SynchronizeIrql,
    00041     IN KINTERRUPT_MODE InterruptMode,
    00042     IN BOOLEAN ShareVector,
    00043     IN CCHAR ProcessorNumber,
    00044     IN BOOLEAN FloatingSave
    00045     )
    00046
    00047 /*++
    00048
    00049 Routine Description:
    00050
    00051     This function initializes a kernel interrupt object. The service routine,
    00052     service context, spin lock, vector, IRQL, Synchronized IRQL, and floating
    00053     context save flag are initialized.
    00054
    00055 Arguments:
    00056
    00057     Interrupt - Supplies a pointer to a control object of type interrupt.
    00058
    00059     ServiceRoutine - Supplies a pointer to a function that is to be
    00060         executed when an interrupt occurs via the specified interrupt
    00061         vector.
    00062
    00063     ServiceContext - Supplies a pointer to an arbitrary data structure which is
    00064         to be passed to the function specified by the ServiceRoutine parameter.
    00065
    00066     SpinLock - Supplies a pointer to an executive spin lock.
    00067
    00068     Vector - Supplies the index of the entry in the Interrupt Dispatch Table
    00069         that is to be associated with the ServiceRoutine function.
    00070
    00071     Irql - Supplies the request priority of the interrupting source.
    00072
    00073     SynchronizeIrql - The request priority that the interrupt should be
    00074         synchronized with.
    00075
    00076     InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
    00077         Latched.
    00078
    00079     ShareVector - Supplies a boolean value that specifies whether the
    00080         vector can be shared with other interrupt objects or not.  If FALSE
    00081         then the vector may not be shared, if TRUE it may be.
    00082         Latched.
    00083
    00084     ProcessorNumber - Supplies the number of the processor to which the
    00085         interrupt will be connected.
    00086
    00087     FloatingSave - Supplies a boolean value that determines whether the
    00088         floating point registers and pipe line are to be saved before calling
    00089         the ServiceRoutine function.
    00090         (currently ignored on PowerPC).
    00091
    00092 Return Value:
    00093
    00094     None.
    00095
    00096 --*/
    00097
    00098 {
    00099     //
    00100     // Initialize standard control object header.
    00101     //
    00102
    00103     Interrupt->Type = InterruptObject;
    00104     Interrupt->Size = sizeof(KINTERRUPT);
    00105
    00106     //
    00107     // Initialize the address of the service routine, the service context,
    00108     // the address of the spin lock, the address of the actual spin lock
    00109     // that will be used, the vector number, the IRQL of the interrupting
    00110     // source, the Synchronized IRQL of the interrupt object, the interrupt
    00111     // mode, the processor number, and the floating context save flag.
    00112     //
    00113
    00114     Interrupt->ServiceRoutine = ServiceRoutine;
    00115     Interrupt->ServiceContext = ServiceContext;
    00116
    00117     Interrupt->SpinLock = 0;
    00118     if (ARGUMENT_PRESENT(SpinLock)) {
    00119         Interrupt->ActualLock = SpinLock;
    00120     } else {
    00121         Interrupt->ActualLock = &Interrupt->SpinLock;
    00122     }
    00123
    00124     Interrupt->Vector = Vector;
    00125     Interrupt->Irql = Irql;
    00126     Interrupt->SynchronizeIrql = SynchronizeIrql;
    00127     Interrupt->Mode = InterruptMode;
    00128     Interrupt->ShareVector = ShareVector;
    00129     Interrupt->Number = ProcessorNumber;
    00130     Interrupt->FloatingSave = FloatingSave;
    00131
    00132     //
    00133     // Set the connected state of the interrupt object to FALSE.
    00134     //
    00135
    00136     Interrupt->Connected = FALSE;
    00137     return;
    00138 }
    00139
    00140 BOOLEAN
    00141 KeConnectInterrupt (
    00142     IN PKINTERRUPT Interrupt
    00143     )
    00144
    00145 /*++
    00146
    00147 Routine Description:
    00148
    00149     This function connects an interrupt object to the interrupt vector
    00150     specified by the interrupt object. If the interrupt object is already
    00151     connected, or an attempt is made to connect to an interrupt that cannot
    00152     be connected, then a value of FALSE is returned. Else the specified
    00153     interrupt object is connected to the interrupt vector, the connected
    00154     state is set to TRUE, and TRUE is returned as the function value.
    00155
    00156 Arguments:
    00157
    00158     Interrupt - Supplies a pointer to a control object of type interrupt.
    00159
    00160 Return Value:
    00161
    00162     If the interrupt object is already connected or an attempt is made to
    00163     connect to an interrupt vector that cannot be connected, then a value
    00164     of FALSE is returned. Else a value of TRUE is returned.
    00165
    00166 --*/
    00167
    00168 {
    00169
    00170     BOOLEAN Connected;
    00171     PKINTERRUPT Interruptx;
    00172     KIRQL Irql;
    00173     CHAR Number;
    00174     KIRQL OldIrql;
    00175     KIRQL PreviousIrql;
    00176     ULONG Vector;
    00177
    00178     //
    00179     // If the interrupt object is already connected, the interrupt vector
    00180     // number is invalid, an attempt is being made to connect to a vector
    00181     // that cannot be connected, the interrupt request level is invalid,
    00182     // the processor number is invalid, of the interrupt vector is less
    00183     // than or equal to the highest level and it not equal to the specified
    00184     // IRQL, then do not connect the interrupt object. Else connect interrupt
    00185     // object to the specified vector and establish the proper interrupt
    00186     // dispatcher.
    00187     //
    00188
    00189     Connected = FALSE;
    00190     Irql = Interrupt->Irql;
    00191     Number = Interrupt->Number;
    00192     Vector = Interrupt->Vector;
    00193     if (
    00194         (Vector < MAXIMUM_VECTOR) &&            // will fit in interrupt table
    00195         (Irql <= HIGH_LEVEL) &&                 // is at a reasonable priority
    00196         (Number < KeNumberProcessors) &&        // can run on a cpu we have
    00197         (
    00198             (Vector > HIGH_LEVEL) ||            // and is either EISA or
    00199             ((PCR->ReservedVectors & (1 << Vector)) == 0) // is NOT reserved
    00200         )
    00201     ) {
    00202
    00203         //
    00204         //
    00205         // Set system affinity to the specified processor.
    00206         //
    00207
    00208         KeSetSystemAffinityThread((KAFFINITY)(1 << Number));
    00209
    00210         //
    00211         // Raise IRQL to dispatcher level and lock dispatcher database.
    00212         //
    00213
    00214         KiLockDispatcherDatabase(&OldIrql);
    00215
    00216         //
    00217         // If the specified interrupt vector is not connected, then
    00218         // connect the interrupt vector to the interrupt dispatcher
    00219         // and set the new interrupt mode and enable masks.
    00220         // Else if the interrupt is
    00221         // already chained, then add the new interrupt object at the end
    00222         // of the chain. If the interrupt vector is not chained, then
    00223         // start a chain with the previous interrupt object at the front
    00224         // of the chain. The interrupt mode of all interrupt objects in
    00225         // a chain must be the same.
    00226         //
    00227
    00228         if (Interrupt->Connected == FALSE) {
    00229             if (PCR->InterruptRoutine[Vector] ==
    00230                 (PKINTERRUPT_ROUTINE)(&KxUnexpectedInterrupt.DispatchCode)) {
    00231                 Connected = TRUE;
    00232                 Interrupt->Connected = TRUE;
    00233                 if (Interrupt->FloatingSave) {
    00234                     Interrupt->DispatchAddress = KiFloatingDispatch;
    00235
    00236                 } else {
    00237                     if (Interrupt->Irql == Interrupt->SynchronizeIrql) {
    00238 #if defined(NT_UP)
    00239                         Interrupt->DispatchAddress =
    00240                                  (PKINTERRUPT_ROUTINE)Interrupt->ServiceRoutine;
    00241 #else
    00242                         Interrupt->DispatchAddress =
    00243                                  (PKINTERRUPT_ROUTINE)KiInterruptDispatchSame;
    00244 #endif
    00245
    00246                     } else {
    00247                         Interrupt->DispatchAddress =
    00248                                  (PKINTERRUPT_ROUTINE)KiInterruptDispatchRaise;
    00249                     }
    00250                 }
    00251
    00252                 //
    00253                 // Copy the function descriptor for the Dispatch routine
    00254                 // into DispatchCode.  This will be used by KiInterruptEx-
    00255                 // ception to dispatch the interrupt.
    00256                 //
    00257
    00258                 Interrupt->DispatchCode[0] =
    00259                                 *(PULONG)(Interrupt->DispatchAddress);
    00260                 Interrupt->DispatchCode[1] =
    00261                                 *(((PULONG)(Interrupt->DispatchAddress))+1);
    00262                 PCR->InterruptRoutine[Vector] =
    00263                             (PKINTERRUPT_ROUTINE)Interrupt->DispatchCode;
    00264
    00265                 HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode);
    00266
    00267             } else if (Interrupt->ShareVector) {
    00268                 Interruptx = CONTAINING_RECORD(PCR->InterruptRoutine[Vector],
    00269                                                KINTERRUPT,
    00270                                                DispatchCode[0]);
    00271                 if (Interruptx->ShareVector &&
    00272                     Interrupt->Mode == Interruptx->Mode) {
    00273                     Connected = TRUE;
    00274                     Interrupt->Connected = TRUE;
    00275                     KeRaiseIrql((KIRQL)(max(Irql, SYNCH_LEVEL)), &PreviousIrql);
    00276                     if (Interruptx->DispatchAddress !=
    00277                                     (PKINTERRUPT_ROUTINE)KiChainedDispatch) {
    00278                         InitializeListHead(&Interruptx->InterruptListEntry);
    00279                         Interruptx->DispatchAddress =
    00280                                         (PKINTERRUPT_ROUTINE)KiChainedDispatch;
    00281                         Interruptx->DispatchCode[0] =
    00282                                         *(PULONG)KiChainedDispatch;
    00283                         Interruptx->DispatchCode[1] =
    00284                                         *(((PULONG)KiChainedDispatch)+1);
    00285                     }
    00286
    00287                     InsertTailList(&Interruptx->InterruptListEntry,
    00288                                    &Interrupt->InterruptListEntry);
    00289                     KeLowerIrql(PreviousIrql);
    00290                 }
    00291             }
    00292         }
    00293
    00294         //
    00295         // Unlock dispatcher database and lower IRQL to its previous value.
    00296         //
    00297
    00298         KiUnlockDispatcherDatabase(OldIrql);
    00299
    00300         //
    00301         // Set system affinity back to the original value.
    00302         //
    00303
    00304         KeRevertToUserAffinityThread();
    00305     }
    00306
    00307     //
    00308     // Return whether interrupt was connected to the specified vector.
    00309     //
    00310
    00311     return Connected;
    00312 }
    00313
    00314 BOOLEAN
    00315 KeDisconnectInterrupt (
    00316     IN PKINTERRUPT Interrupt
    00317     )
    00318
    00319 /*++
    00320
    00321 Routine Description:
    00322
    00323     This function disconnects an interrupt object from the interrupt vector
    00324     specified by the interrupt object. If the interrupt object is not
    00325     connected, then a value of FALSE is returned. Else the specified interrupt
    00326     object is disconnected from the interrupt vector, the connected state is
    00327     set to FALSE, and TRUE is returned as the function value.
    00328
    00329 Arguments:
    00330
    00331     Interrupt - Supplies a pointer to a control object of type interrupt.
    00332
    00333 Return Value:
    00334
    00335     If the interrupt object is not connected, then a value of FALSE is
    00336     returned. Else a value of TRUE is returned.
    00337
    00338 --*/
    00339
    00340 {
    00341
    00342     BOOLEAN Connected;
    00343     PKINTERRUPT Interruptx;
    00344     PKINTERRUPT Interrupty;
    00345     KIRQL Irql;
    00346     KIRQL OldIrql;
    00347     KIRQL PreviousIrql;
    00348     ULONG Vector;
    00349
    00350     //
    00351     // Set system affinity to the specified processor.
    00352     //
    00353
    00354     KeSetSystemAffinityThread((KAFFINITY)(1 << Interrupt->Number));
    00355
    00356     //
    00357     // Raise IRQL to dispatcher level and lock dispatcher database.
    00358     //
    00359
    00360     KiLockDispatcherDatabase(&OldIrql);
    00361
    00362     //
    00363     // If the interrupt object is connected, then disconnect it from the
    00364     // specified vector.
    00365     //
    00366
    00367     Connected = Interrupt->Connected;
    00368     if (Connected != FALSE) {
    00369         Irql = Interrupt->Irql;
    00370         Vector = Interrupt->Vector;
    00371
    00372         //
    00373         // If the specified interrupt vector is not connected to the chained
    00374         // interrupt dispatcher, then disconnect it by setting its dispatch
    00375         // address to the unexpected interrupt routine. Else remove the
    00376         // interrupt object from the interrupt chain. If there is only
    00377         // one entry remaining in the list, then reestablish the dispatch
    00378         // address.
    00379         //
    00380
    00381         Interruptx = CONTAINING_RECORD(PCR->InterruptRoutine[Vector],
    00382                                        KINTERRUPT,
    00383                                        DispatchCode[0]);
    00384
    00385         if (Interruptx->DispatchAddress ==
    00386                                 (PKINTERRUPT_ROUTINE)KiChainedDispatch) {
    00387             KeRaiseIrql((KIRQL)(max(Irql, SYNCH_LEVEL)), &PreviousIrql);
    00388             if (Interrupt == Interruptx) {
    00389                 Interruptx = CONTAINING_RECORD(Interruptx->InterruptListEntry.Flink,
    00390                                                KINTERRUPT, InterruptListEntry);
    00391                 Interruptx->DispatchAddress =
    00392                                 (PKINTERRUPT_ROUTINE)KiChainedDispatch;
    00393                 Interruptx->DispatchCode[0] = *(PULONG)KiChainedDispatch;
    00394                 Interruptx->DispatchCode[1] = *(((PULONG)KiChainedDispatch)+1);
    00395                 PCR->InterruptRoutine[Vector] =
    00396                                 (PKINTERRUPT_ROUTINE)Interruptx->DispatchCode;
    00397
    00398             }
    00399
    00400             RemoveEntryList(&Interrupt->InterruptListEntry);
    00401             Interrupty = CONTAINING_RECORD(Interruptx->InterruptListEntry.Flink,
    00402                                            KINTERRUPT,
    00403                                            InterruptListEntry);
    00404
    00405             if (Interruptx == Interrupty) {
    00406                 if (Interrupt->FloatingSave) {
    00407                     Interrupt->DispatchAddress = KiFloatingDispatch;
    00408
    00409                 } else {
    00410                     if (Interrupt->Irql == Interrupt->SynchronizeIrql) {
    00411 #if defined(NT_UP)
    00412                         Interrupt->DispatchAddress =
    00413                                  (PKINTERRUPT_ROUTINE)Interrupt->ServiceRoutine;
    00414 #else
    00415                         Interrupt->DispatchAddress =
    00416                                  (PKINTERRUPT_ROUTINE)KiInterruptDispatchSame;
    00417 #endif
    00418
    00419                     } else {
    00420                         Interrupt->DispatchAddress =
    00421                                  (PKINTERRUPT_ROUTINE)KiInterruptDispatchRaise;
    00422                     }
    00423                 }
    00424
    00425                 //
    00426                 // Copy the function descriptor for the Dispatch routine
    00427                 // into DispatchCode.  This will be used by KiInterruptEx-
    00428                 // ception to dispatch the interrupt.
    00429                 //
    00430                 Interrupty->DispatchCode[0] =
    00431                                 *(PULONG)(Interrupty->DispatchAddress);
    00432                 Interrupty->DispatchCode[1] =
    00433                                 *(((PULONG)(Interrupty->DispatchAddress))+1);
    00434                 PCR->InterruptRoutine[Vector] =
    00435                                (PKINTERRUPT_ROUTINE)Interrupty->DispatchCode;
    00436
    00437                 }
    00438
    00439             KeLowerIrql(PreviousIrql);
    00440
    00441         } else {
    00442             HalDisableSystemInterrupt(Vector, Irql);
    00443             PCR->InterruptRoutine[Vector] =
    00444                     (PKINTERRUPT_ROUTINE)(&KxUnexpectedInterrupt.DispatchCode);
    00445         }
    00446 #ifdef NOTDEF
    00447         KeSweepIcache(TRUE);
    00448 #endif
    00449         Interrupt->Connected = FALSE;
    00450     }
    00451
    00452     //
    00453     // Unlock dispatcher database and lower IRQL to its previous value.
    00454     //
    00455
    00456     KiUnlockDispatcherDatabase(OldIrql);
    00457
    00458     //
    00459     // Set system affinity back to the original value.
    00460     //
    00461
    00462     KeRevertToUserAffinityThread();
    00463
    00464     //
    00465     // Return whether interrupt was disconnected from the specified vector.
    00466     //
    00467
    00468     return Connected;
    00469 }