xref: /reactos/ntoskrnl/ke/amd64/interrupt.c (revision 990ba545)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/ke/amd64/interrupt.c
5  * PURPOSE:         Manages the Kernel's IRQ support for external drivers,
6  *                  for the purpopses of connecting, disconnecting and setting
7  *                  up ISRs for drivers. The backend behind the Io* Interrupt
8  *                  routines.
9  * PROGRAMMERS:     Timo Kreuzer (timo.kreuzer@reactos.org)
10  *                  Alex Ionescu (alex.ionescu@reactos.org)
11  */
12 
13 /* INCLUDES *****************************************************************/
14 
15 #include <ntoskrnl.h>
16 #define NDEBUG
17 #include <debug.h>
18 
19 extern UCHAR KiInterruptDispatchTemplate[16];
20 extern UCHAR KiUnexpectedRange[];
21 extern UCHAR KiUnexpectedRangeEnd[];
22 void KiInterruptDispatch(void);
23 
24 
25 /* FUNCTIONS ****************************************************************/
26 
27 VOID
28 NTAPI
29 KeInitializeInterrupt(
30     IN PKINTERRUPT Interrupt,
31     IN PKSERVICE_ROUTINE ServiceRoutine,
32     IN PVOID ServiceContext,
33     IN PKSPIN_LOCK SpinLock,
34     IN ULONG Vector,
35     IN KIRQL Irql,
36     IN KIRQL SynchronizeIrql,
37     IN KINTERRUPT_MODE InterruptMode,
38     IN BOOLEAN ShareVector,
39     IN CHAR ProcessorNumber,
40     IN BOOLEAN FloatingSave)
41 {
42 
43     /* Initialize the header */
44     Interrupt->Type = InterruptObject;
45     Interrupt->Size = sizeof(KINTERRUPT);
46 
47     /* If no Spinlock is given, use the internal */
48     if (!SpinLock) SpinLock = &Interrupt->SpinLock;
49     KeInitializeSpinLock(&Interrupt->SpinLock);
50 
51     /* Set the given parameters */
52     Interrupt->ServiceRoutine = ServiceRoutine;
53     Interrupt->ServiceContext = ServiceContext;
54     Interrupt->ActualLock = SpinLock;
55     Interrupt->Vector = Vector;
56     Interrupt->Irql = Irql;
57     Interrupt->SynchronizeIrql = SynchronizeIrql;
58     Interrupt->Mode = InterruptMode;
59     Interrupt->ShareVector = ShareVector;
60     Interrupt->Number = ProcessorNumber;
61     Interrupt->FloatingSave = FloatingSave;
62 
63     /* Set initial values */
64     Interrupt->TickCount = 0;
65     Interrupt->Connected = FALSE;
66     Interrupt->ServiceCount = 0;
67     Interrupt->DispatchCount = 0;
68     Interrupt->TrapFrame = NULL;
69     Interrupt->Reserved = 0;
70 
71     /* Copy the dispatch code (its location independent, no need to patch it) */
72     RtlCopyMemory(Interrupt->DispatchCode,
73                   KiInterruptDispatchTemplate,
74                   sizeof(Interrupt->DispatchCode));
75 
76     Interrupt->DispatchAddress = 0;
77 }
78 
79 BOOLEAN
80 NTAPI
81 KeConnectInterrupt(IN PKINTERRUPT Interrupt)
82 {
83     PVOID CurrentHandler;
84     PKINTERRUPT ConnectedInterrupt;
85 
86     ASSERT(Interrupt->Vector >= PRIMARY_VECTOR_BASE);
87     ASSERT(Interrupt->Vector <= MAXIMUM_IDTVECTOR);
88     ASSERT(Interrupt->Number < KeNumberProcessors);
89     ASSERT(Interrupt->Irql <= HIGH_LEVEL);
90     ASSERT(Interrupt->SynchronizeIrql >= Interrupt->Irql);
91     ASSERT(Interrupt->Irql == (Interrupt->Vector >> 4));
92 
93     /* Check if its already connected */
94     if (Interrupt->Connected) return TRUE;
95 
96     /* Query the current handler */
97     CurrentHandler = KeQueryInterruptHandler(Interrupt->Vector);
98 
99     /* Check if the vector is unused */
100     if ((CurrentHandler >= (PVOID)KiUnexpectedRange) &&
101         (CurrentHandler <= (PVOID)KiUnexpectedRangeEnd))
102     {
103         /* Initialize the list for chained interrupts */
104         InitializeListHead(&Interrupt->InterruptListEntry);
105 
106         /* Set normal dispatch address */
107         Interrupt->DispatchAddress = KiInterruptDispatch;
108 
109         /* Set the new handler */
110         KeRegisterInterruptHandler(Interrupt->Vector,
111                                    Interrupt->DispatchCode);
112 
113         /* Enable the interrupt */
114         if (!HalEnableSystemInterrupt(Interrupt->Vector,
115                                       Interrupt->Irql,
116                                       Interrupt->Mode))
117         {
118             /* Didn't work, restore old handler */
119             DPRINT1("HalEnableSystemInterrupt failed\n");
120             KeRegisterInterruptHandler(Interrupt->Vector, CurrentHandler);
121             return FALSE;
122         }
123     }
124     else
125     {
126         /* Get the connected interrupt */
127         ConnectedInterrupt = CONTAINING_RECORD(CurrentHandler, KINTERRUPT, DispatchCode);
128 
129         /* Check if sharing is ok */
130         if ((Interrupt->ShareVector == 0) ||
131             (ConnectedInterrupt->ShareVector == 0) ||
132             (Interrupt->Mode != ConnectedInterrupt->Mode))
133         {
134             return FALSE;
135         }
136 
137         /* Insert the new interrupt into the connected interrupt's list */
138         InsertTailList(&ConnectedInterrupt->InterruptListEntry,
139                        &Interrupt->InterruptListEntry);
140     }
141 
142     /* Mark as connected */
143     Interrupt->Connected = TRUE;
144 
145     return TRUE;
146 }
147 
148 BOOLEAN
149 NTAPI
150 KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)
151 {
152     /* If the interrupt wasn't connected, there's nothing to do */
153     if (!Interrupt->Connected)
154     {
155         return FALSE;
156     }
157 
158     UNIMPLEMENTED;
159     __debugbreak();
160     return TRUE;
161 }
162 
163 BOOLEAN
164 NTAPI
165 KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt,
166                        IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
167                        IN PVOID SynchronizeContext OPTIONAL)
168 {
169     BOOLEAN Success;
170     KIRQL OldIrql;
171 
172     /* Raise IRQL */
173     OldIrql = KfRaiseIrql(Interrupt->SynchronizeIrql);
174 
175     /* Acquire interrupt spinlock */
176     KeAcquireSpinLockAtDpcLevel(Interrupt->ActualLock);
177 
178     /* Call the routine */
179     Success = SynchronizeRoutine(SynchronizeContext);
180 
181     /* Release lock */
182     KeReleaseSpinLockFromDpcLevel(Interrupt->ActualLock);
183 
184     /* Lower IRQL */
185     KeLowerIrql(OldIrql);
186 
187     /* Return status */
188     return Success;
189 }
190