xref: /reactos/ntoskrnl/ke/i386/irqobj.c (revision 2d442956)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * PROJECT:         ReactOS Kernel
3c2c66affSColin Finck  * LICENSE:         GPL - See COPYING in the top level directory
4c2c66affSColin Finck  * FILE:            ntoskrnl/ke/i386/irqobj.c
5c2c66affSColin Finck  * PURPOSE:         Manages the Kernel's IRQ support for external drivers,
6c2c66affSColin Finck  *                  for the purposes of connecting, disconnecting and setting
7c2c66affSColin Finck  *                  up ISRs for drivers. The backend behind the Io* Interrupt
8c2c66affSColin Finck  *                  routines.
9c2c66affSColin Finck  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
10c2c66affSColin Finck  */
11c2c66affSColin Finck 
12c2c66affSColin Finck /* INCLUDES *****************************************************************/
13c2c66affSColin Finck 
14c2c66affSColin Finck #include <ntoskrnl.h>
15c2c66affSColin Finck #define NDEBUG
16c2c66affSColin Finck #include <debug.h>
17c2c66affSColin Finck 
18c2c66affSColin Finck /* GLOBALS *******************************************************************/
19c2c66affSColin Finck 
20c2c66affSColin Finck ULONG KiISRTimeout = 55;
21c2c66affSColin Finck USHORT KiISROverflow = 30000;
22c2c66affSColin Finck extern ULONG NTAPI KiChainedDispatch2ndLvl(VOID);
23c2c66affSColin Finck 
24c2c66affSColin Finck /* PRIVATE FUNCTIONS *********************************************************/
25c2c66affSColin Finck 
26c2c66affSColin Finck VOID
27c2c66affSColin Finck NTAPI
KiGetVectorDispatch(IN ULONG Vector,IN PDISPATCH_INFO Dispatch)28c2c66affSColin Finck KiGetVectorDispatch(IN ULONG Vector,
29c2c66affSColin Finck                     IN PDISPATCH_INFO Dispatch)
30c2c66affSColin Finck {
31c2c66affSColin Finck     PKINTERRUPT_ROUTINE Handler;
32c2c66affSColin Finck     PVOID Current;
33c2c66affSColin Finck     UCHAR Type;
34c2c66affSColin Finck     UCHAR Entry;
35c2c66affSColin Finck 
36c2c66affSColin Finck     /* Check if this is a primary or 2nd-level dispatch */
37c2c66affSColin Finck     Type = HalSystemVectorDispatchEntry(Vector,
38c2c66affSColin Finck                                         &Dispatch->FlatDispatch,
39c2c66affSColin Finck                                         &Dispatch->NoDispatch);
40c2c66affSColin Finck     ASSERT(Type == 0);
41c2c66affSColin Finck 
42c2c66affSColin Finck     /* Get the IDT entry for this vector */
43c2c66affSColin Finck     Entry = HalVectorToIDTEntry(Vector);
44c2c66affSColin Finck 
45c2c66affSColin Finck     /* Setup the unhandled dispatch */
46c2c66affSColin Finck     Dispatch->NoDispatch = (PVOID)(((ULONG_PTR)&KiStartUnexpectedRange) +
47c2c66affSColin Finck                                    (Entry - PRIMARY_VECTOR_BASE) *
48c2c66affSColin Finck                                    KiUnexpectedEntrySize);
49c2c66affSColin Finck 
50c2c66affSColin Finck     /* Setup the handlers */
51c2c66affSColin Finck     Dispatch->InterruptDispatch = (PVOID)KiInterruptDispatch;
52c2c66affSColin Finck     Dispatch->FloatingDispatch = NULL; // Floating Interrupts are not supported
53c2c66affSColin Finck     Dispatch->ChainedDispatch = (PVOID)KiChainedDispatch;
54c2c66affSColin Finck     Dispatch->FlatDispatch = NULL;
55c2c66affSColin Finck 
56c2c66affSColin Finck     /* Get the current handler */
57c2c66affSColin Finck     Current = KeQueryInterruptHandler(Vector);
58c2c66affSColin Finck 
59c2c66affSColin Finck     /* Set the interrupt */
60c2c66affSColin Finck     Dispatch->Interrupt = CONTAINING_RECORD(Current,
61c2c66affSColin Finck                                             KINTERRUPT,
62c2c66affSColin Finck                                             DispatchCode);
63c2c66affSColin Finck 
64c2c66affSColin Finck     /* Check what this interrupt is connected to */
65c2c66affSColin Finck     if ((PKINTERRUPT_ROUTINE)Current == Dispatch->NoDispatch)
66c2c66affSColin Finck     {
67c2c66affSColin Finck         /* Not connected */
68c2c66affSColin Finck         Dispatch->Type = NoConnect;
69c2c66affSColin Finck     }
70c2c66affSColin Finck     else
71c2c66affSColin Finck     {
72c2c66affSColin Finck         /* Get the handler */
73c2c66affSColin Finck         Handler = Dispatch->Interrupt->DispatchAddress;
74c2c66affSColin Finck         if (Handler == Dispatch->ChainedDispatch)
75c2c66affSColin Finck         {
76c2c66affSColin Finck             /* It's a chained interrupt */
77c2c66affSColin Finck             Dispatch->Type = ChainConnect;
78c2c66affSColin Finck         }
79c2c66affSColin Finck         else if ((Handler == Dispatch->InterruptDispatch) ||
80c2c66affSColin Finck                  (Handler == Dispatch->FloatingDispatch))
81c2c66affSColin Finck         {
82c2c66affSColin Finck             /* It's unchained */
83c2c66affSColin Finck             Dispatch->Type = NormalConnect;
84c2c66affSColin Finck         }
85c2c66affSColin Finck         else
86c2c66affSColin Finck         {
87c2c66affSColin Finck             /* Unknown */
88c2c66affSColin Finck             Dispatch->Type = UnknownConnect;
89c2c66affSColin Finck         }
90c2c66affSColin Finck     }
91c2c66affSColin Finck }
92c2c66affSColin Finck 
93c2c66affSColin Finck VOID
94c2c66affSColin Finck NTAPI
KiConnectVectorToInterrupt(IN PKINTERRUPT Interrupt,IN CONNECT_TYPE Type)95c2c66affSColin Finck KiConnectVectorToInterrupt(IN PKINTERRUPT Interrupt,
96c2c66affSColin Finck                            IN CONNECT_TYPE Type)
97c2c66affSColin Finck {
98c2c66affSColin Finck     DISPATCH_INFO Dispatch;
99c2c66affSColin Finck     PKINTERRUPT_ROUTINE Handler;
100c2c66affSColin Finck 
101c2c66affSColin Finck     /* Get vector data */
102c2c66affSColin Finck     KiGetVectorDispatch(Interrupt->Vector, &Dispatch);
103c2c66affSColin Finck 
104c2c66affSColin Finck     /* Check if we're only disconnecting */
105c2c66affSColin Finck     if (Type == NoConnect)
106c2c66affSColin Finck     {
107c2c66affSColin Finck         /* Set the handler to NoDispatch */
108c2c66affSColin Finck         Handler = Dispatch.NoDispatch;
109c2c66affSColin Finck     }
110c2c66affSColin Finck     else
111c2c66affSColin Finck     {
112c2c66affSColin Finck         /* Get the right handler */
113c2c66affSColin Finck         Handler = (Type == NormalConnect) ?
114c2c66affSColin Finck                   Dispatch.InterruptDispatch:
115c2c66affSColin Finck                   Dispatch.ChainedDispatch;
116c2c66affSColin Finck         ASSERT(Interrupt->FloatingSave == FALSE);
117c2c66affSColin Finck 
118c2c66affSColin Finck         /* Set the handler */
119c2c66affSColin Finck         Interrupt->DispatchAddress = Handler;
120c2c66affSColin Finck 
121c2c66affSColin Finck         /* Read note in trap.s -- patching not needed since JMP is static */
122c2c66affSColin Finck 
123c2c66affSColin Finck         /* Now set the final handler address */
124c2c66affSColin Finck         ASSERT(Dispatch.FlatDispatch == NULL);
125c2c66affSColin Finck         Handler = (PVOID)&Interrupt->DispatchCode;
126c2c66affSColin Finck     }
127c2c66affSColin Finck 
128c2c66affSColin Finck     /* Register the interrupt */
129c2c66affSColin Finck     KeRegisterInterruptHandler(Interrupt->Vector, Handler);
130c2c66affSColin Finck }
131c2c66affSColin Finck 
132c2c66affSColin Finck FORCEINLINE
133c2c66affSColin Finck DECLSPEC_NORETURN
134c2c66affSColin Finck VOID
KiExitInterrupt(IN PKTRAP_FRAME TrapFrame,IN KIRQL OldIrql,IN BOOLEAN Spurious)135c2c66affSColin Finck KiExitInterrupt(IN PKTRAP_FRAME TrapFrame,
136c2c66affSColin Finck                 IN KIRQL OldIrql,
137c2c66affSColin Finck                 IN BOOLEAN Spurious)
138c2c66affSColin Finck {
139c2c66affSColin Finck     /* Check if this was a real interrupt */
140c2c66affSColin Finck     if (!Spurious)
141c2c66affSColin Finck     {
142c2c66affSColin Finck         /* It was, disable interrupts and restore the IRQL */
143c2c66affSColin Finck         _disable();
144c2c66affSColin Finck         HalEndSystemInterrupt(OldIrql, TrapFrame);
145c2c66affSColin Finck     }
146c2c66affSColin Finck 
147c2c66affSColin Finck     /* Now exit the trap */
148c2c66affSColin Finck     KiEoiHelper(TrapFrame);
149c2c66affSColin Finck }
150c2c66affSColin Finck 
151c2c66affSColin Finck DECLSPEC_NORETURN
152c2c66affSColin Finck VOID
153c2c66affSColin Finck __cdecl
KiUnexpectedInterrupt(VOID)154c2c66affSColin Finck KiUnexpectedInterrupt(VOID)
155c2c66affSColin Finck {
156c2c66affSColin Finck     /* Crash the machine */
157c2c66affSColin Finck     KeBugCheck(TRAP_CAUSE_UNKNOWN);
158c2c66affSColin Finck }
159c2c66affSColin Finck 
160c2c66affSColin Finck VOID
161c2c66affSColin Finck FASTCALL
KiUnexpectedInterruptTailHandler(IN PKTRAP_FRAME TrapFrame)162c2c66affSColin Finck KiUnexpectedInterruptTailHandler(IN PKTRAP_FRAME TrapFrame)
163c2c66affSColin Finck {
164c2c66affSColin Finck     KIRQL OldIrql;
165c2c66affSColin Finck 
166c2c66affSColin Finck     /* Enter trap */
167c2c66affSColin Finck     KiEnterInterruptTrap(TrapFrame);
168c2c66affSColin Finck 
169c2c66affSColin Finck     /* Increase interrupt count */
170c2c66affSColin Finck     KeGetCurrentPrcb()->InterruptCount++;
171c2c66affSColin Finck 
172c2c66affSColin Finck     /* Start the interrupt */
173c2c66affSColin Finck     if (HalBeginSystemInterrupt(HIGH_LEVEL, TrapFrame->ErrCode, &OldIrql))
174c2c66affSColin Finck     {
175c2c66affSColin Finck         /* Warn user */
176c2c66affSColin Finck         DPRINT1("\n\x7\x7!!! Unexpected Interrupt 0x%02lx !!!\n", TrapFrame->ErrCode);
177c2c66affSColin Finck 
178c2c66affSColin Finck         /* Now call the epilogue code */
179c2c66affSColin Finck         KiExitInterrupt(TrapFrame, OldIrql, FALSE);
180c2c66affSColin Finck     }
181c2c66affSColin Finck     else
182c2c66affSColin Finck     {
183c2c66affSColin Finck         /* Now call the epilogue code */
184c2c66affSColin Finck         KiExitInterrupt(TrapFrame, OldIrql, TRUE);
185c2c66affSColin Finck     }
186c2c66affSColin Finck }
187c2c66affSColin Finck 
188c2c66affSColin Finck typedef
189c2c66affSColin Finck VOID
190c2c66affSColin Finck (FASTCALL *PKI_INTERRUPT_DISPATCH)(
191c2c66affSColin Finck     IN PKTRAP_FRAME TrapFrame,
192c2c66affSColin Finck     IN PKINTERRUPT Interrupt
193c2c66affSColin Finck );
194c2c66affSColin Finck 
195c2c66affSColin Finck VOID
196c2c66affSColin Finck FASTCALL
KiInterruptDispatch(IN PKTRAP_FRAME TrapFrame,IN PKINTERRUPT Interrupt)197c2c66affSColin Finck KiInterruptDispatch(IN PKTRAP_FRAME TrapFrame,
198c2c66affSColin Finck                     IN PKINTERRUPT Interrupt)
199c2c66affSColin Finck {
200c2c66affSColin Finck     KIRQL OldIrql;
201c2c66affSColin Finck 
202c2c66affSColin Finck     /* Increase interrupt count */
203c2c66affSColin Finck     KeGetCurrentPrcb()->InterruptCount++;
204c2c66affSColin Finck 
205c2c66affSColin Finck     /* Begin the interrupt, making sure it's not spurious */
206c2c66affSColin Finck     if (HalBeginSystemInterrupt(Interrupt->SynchronizeIrql,
207c2c66affSColin Finck                                 Interrupt->Vector,
208c2c66affSColin Finck                                 &OldIrql))
209c2c66affSColin Finck     {
210c2c66affSColin Finck         /* Acquire interrupt lock */
211c2c66affSColin Finck         KxAcquireSpinLock(Interrupt->ActualLock);
212c2c66affSColin Finck 
213c2c66affSColin Finck         /* Call the ISR */
214c2c66affSColin Finck         Interrupt->ServiceRoutine(Interrupt, Interrupt->ServiceContext);
215c2c66affSColin Finck 
216c2c66affSColin Finck         /* Release interrupt lock */
217c2c66affSColin Finck         KxReleaseSpinLock(Interrupt->ActualLock);
218c2c66affSColin Finck 
219c2c66affSColin Finck         /* Now call the epilogue code */
220c2c66affSColin Finck         KiExitInterrupt(TrapFrame, OldIrql, FALSE);
221c2c66affSColin Finck     }
222c2c66affSColin Finck     else
223c2c66affSColin Finck     {
224c2c66affSColin Finck         /* Now call the epilogue code */
225c2c66affSColin Finck         KiExitInterrupt(TrapFrame, OldIrql, TRUE);
226c2c66affSColin Finck     }
227c2c66affSColin Finck }
228c2c66affSColin Finck 
229c2c66affSColin Finck VOID
230c2c66affSColin Finck FASTCALL
KiChainedDispatch(IN PKTRAP_FRAME TrapFrame,IN PKINTERRUPT Interrupt)231c2c66affSColin Finck KiChainedDispatch(IN PKTRAP_FRAME TrapFrame,
232c2c66affSColin Finck                   IN PKINTERRUPT Interrupt)
233c2c66affSColin Finck {
234c2c66affSColin Finck     KIRQL OldIrql, OldInterruptIrql = 0;
235c2c66affSColin Finck     BOOLEAN Handled;
236c2c66affSColin Finck     PLIST_ENTRY NextEntry, ListHead;
237c2c66affSColin Finck 
238c2c66affSColin Finck     /* Increase interrupt count */
239c2c66affSColin Finck     KeGetCurrentPrcb()->InterruptCount++;
240c2c66affSColin Finck 
241c2c66affSColin Finck     /* Begin the interrupt, making sure it's not spurious */
242c2c66affSColin Finck     if (HalBeginSystemInterrupt(Interrupt->Irql,
243c2c66affSColin Finck                                 Interrupt->Vector,
244c2c66affSColin Finck                                 &OldIrql))
245c2c66affSColin Finck     {
246c2c66affSColin Finck         /* Get list pointers */
247c2c66affSColin Finck         ListHead = &Interrupt->InterruptListEntry;
248c2c66affSColin Finck         NextEntry = ListHead; /* The head is an entry! */
249c2c66affSColin Finck         while (TRUE)
250c2c66affSColin Finck         {
251c2c66affSColin Finck             /* Check if this interrupt's IRQL is higher than the current one */
252c2c66affSColin Finck             if (Interrupt->SynchronizeIrql > Interrupt->Irql)
253c2c66affSColin Finck             {
254c2c66affSColin Finck                 /* Raise to higher IRQL */
255c2c66affSColin Finck                 OldInterruptIrql = KfRaiseIrql(Interrupt->SynchronizeIrql);
256c2c66affSColin Finck             }
257c2c66affSColin Finck 
258c2c66affSColin Finck             /* Acquire interrupt lock */
259c2c66affSColin Finck             KxAcquireSpinLock(Interrupt->ActualLock);
260c2c66affSColin Finck 
261c2c66affSColin Finck             /* Call the ISR */
262c2c66affSColin Finck             Handled = Interrupt->ServiceRoutine(Interrupt,
263c2c66affSColin Finck                                                 Interrupt->ServiceContext);
264c2c66affSColin Finck 
265c2c66affSColin Finck             /* Release interrupt lock */
266c2c66affSColin Finck             KxReleaseSpinLock(Interrupt->ActualLock);
267c2c66affSColin Finck 
268c2c66affSColin Finck             /* Check if this interrupt's IRQL is higher than the current one */
269c2c66affSColin Finck             if (Interrupt->SynchronizeIrql > Interrupt->Irql)
270c2c66affSColin Finck             {
271c2c66affSColin Finck                 /* Lower the IRQL back */
272c2c66affSColin Finck                 ASSERT(OldInterruptIrql == Interrupt->Irql);
273c2c66affSColin Finck                 KfLowerIrql(OldInterruptIrql);
274c2c66affSColin Finck             }
275c2c66affSColin Finck 
276c2c66affSColin Finck             /* Check if the interrupt got handled and it's level */
277c2c66affSColin Finck             if ((Handled) && (Interrupt->Mode == LevelSensitive)) break;
278c2c66affSColin Finck 
279c2c66affSColin Finck             /* What's next? */
280c2c66affSColin Finck             NextEntry = NextEntry->Flink;
281c2c66affSColin Finck 
282c2c66affSColin Finck             /* Is this the last one? */
283c2c66affSColin Finck             if (NextEntry == ListHead)
284c2c66affSColin Finck             {
285c2c66affSColin Finck                 /* Level should not have gotten here */
286c2c66affSColin Finck                 if (Interrupt->Mode == LevelSensitive) break;
287c2c66affSColin Finck 
288c2c66affSColin Finck                 /* As for edge, we can only exit once nobody can handle the interrupt */
289c2c66affSColin Finck                 if (!Handled) break;
290c2c66affSColin Finck             }
291c2c66affSColin Finck 
292c2c66affSColin Finck             /* Get the interrupt object for the next pass */
293c2c66affSColin Finck             Interrupt = CONTAINING_RECORD(NextEntry, KINTERRUPT, InterruptListEntry);
294c2c66affSColin Finck         }
295c2c66affSColin Finck 
296c2c66affSColin Finck         /* Now call the epilogue code */
297c2c66affSColin Finck         KiExitInterrupt(TrapFrame, OldIrql, FALSE);
298c2c66affSColin Finck     }
299c2c66affSColin Finck     else
300c2c66affSColin Finck     {
301c2c66affSColin Finck         /* Now call the epilogue code */
302c2c66affSColin Finck         KiExitInterrupt(TrapFrame, OldIrql, TRUE);
303c2c66affSColin Finck     }
304c2c66affSColin Finck }
305c2c66affSColin Finck 
306c2c66affSColin Finck VOID
307c2c66affSColin Finck FASTCALL
KiInterruptTemplateHandler(IN PKTRAP_FRAME TrapFrame,IN PKINTERRUPT Interrupt)308c2c66affSColin Finck KiInterruptTemplateHandler(IN PKTRAP_FRAME TrapFrame,
309c2c66affSColin Finck                            IN PKINTERRUPT Interrupt)
310c2c66affSColin Finck {
311c2c66affSColin Finck     /* Enter interrupt frame */
312c2c66affSColin Finck     KiEnterInterruptTrap(TrapFrame);
313c2c66affSColin Finck 
314c2c66affSColin Finck     /* Call the correct dispatcher */
315c2c66affSColin Finck     ((PKI_INTERRUPT_DISPATCH)Interrupt->DispatchAddress)(TrapFrame, Interrupt);
316c2c66affSColin Finck }
317c2c66affSColin Finck 
318c2c66affSColin Finck 
319c2c66affSColin Finck /* PUBLIC FUNCTIONS **********************************************************/
320c2c66affSColin Finck 
321c2c66affSColin Finck /*
322c2c66affSColin Finck  * @implemented
323c2c66affSColin Finck  */
324c2c66affSColin Finck VOID
325c2c66affSColin Finck NTAPI
KeInitializeInterrupt(IN PKINTERRUPT Interrupt,IN PKSERVICE_ROUTINE ServiceRoutine,IN PVOID ServiceContext,IN PKSPIN_LOCK SpinLock,IN ULONG Vector,IN KIRQL Irql,IN KIRQL SynchronizeIrql,IN KINTERRUPT_MODE InterruptMode,IN BOOLEAN ShareVector,IN CHAR ProcessorNumber,IN BOOLEAN FloatingSave)326c2c66affSColin Finck KeInitializeInterrupt(IN PKINTERRUPT Interrupt,
327c2c66affSColin Finck                       IN PKSERVICE_ROUTINE ServiceRoutine,
328c2c66affSColin Finck                       IN PVOID ServiceContext,
329c2c66affSColin Finck                       IN PKSPIN_LOCK SpinLock,
330c2c66affSColin Finck                       IN ULONG Vector,
331c2c66affSColin Finck                       IN KIRQL Irql,
332c2c66affSColin Finck                       IN KIRQL SynchronizeIrql,
333c2c66affSColin Finck                       IN KINTERRUPT_MODE InterruptMode,
334c2c66affSColin Finck                       IN BOOLEAN ShareVector,
335c2c66affSColin Finck                       IN CHAR ProcessorNumber,
336c2c66affSColin Finck                       IN BOOLEAN FloatingSave)
337c2c66affSColin Finck {
338c2c66affSColin Finck     ULONG i;
339c2c66affSColin Finck     PULONG DispatchCode = &Interrupt->DispatchCode[0], Patch = DispatchCode;
340c2c66affSColin Finck 
341c2c66affSColin Finck     /* Set the Interrupt Header */
342c2c66affSColin Finck     Interrupt->Type = InterruptObject;
343c2c66affSColin Finck     Interrupt->Size = sizeof(KINTERRUPT);
344c2c66affSColin Finck 
345c2c66affSColin Finck     /* Check if we got a spinlock */
346c2c66affSColin Finck     if (SpinLock)
347c2c66affSColin Finck     {
348c2c66affSColin Finck         Interrupt->ActualLock = SpinLock;
349c2c66affSColin Finck     }
350c2c66affSColin Finck     else
351c2c66affSColin Finck     {
352*2d442956SSerge Gautherie         /* Use the built-in one */
353c2c66affSColin Finck         KeInitializeSpinLock(&Interrupt->SpinLock);
354c2c66affSColin Finck         Interrupt->ActualLock = &Interrupt->SpinLock;
355c2c66affSColin Finck     }
356c2c66affSColin Finck 
357c2c66affSColin Finck     /* Set the other settings */
358c2c66affSColin Finck     Interrupt->ServiceRoutine = ServiceRoutine;
359c2c66affSColin Finck     Interrupt->ServiceContext = ServiceContext;
360c2c66affSColin Finck     Interrupt->Vector = Vector;
361c2c66affSColin Finck     Interrupt->Irql = Irql;
362c2c66affSColin Finck     Interrupt->SynchronizeIrql = SynchronizeIrql;
363c2c66affSColin Finck     Interrupt->Mode = InterruptMode;
364c2c66affSColin Finck     Interrupt->ShareVector = ShareVector;
365c2c66affSColin Finck     Interrupt->Number = ProcessorNumber;
366c2c66affSColin Finck     Interrupt->FloatingSave = FloatingSave;
367c2c66affSColin Finck     Interrupt->TickCount = MAXULONG;
368c2c66affSColin Finck     Interrupt->DispatchCount = MAXULONG;
369c2c66affSColin Finck 
370c2c66affSColin Finck     /* Loop the template in memory */
371c2c66affSColin Finck     for (i = 0; i < DISPATCH_LENGTH; i++)
372c2c66affSColin Finck     {
373c2c66affSColin Finck         /* Copy the dispatch code */
374c2c66affSColin Finck         *DispatchCode++ = ((PULONG)KiInterruptTemplate)[i];
375c2c66affSColin Finck     }
376c2c66affSColin Finck 
377c2c66affSColin Finck     /* Jump to the last 4 bytes */
378c2c66affSColin Finck     Patch = (PULONG)((ULONG_PTR)Patch +
379c2c66affSColin Finck                      ((ULONG_PTR)&KiInterruptTemplateObject -
380c2c66affSColin Finck                       (ULONG_PTR)KiInterruptTemplate) - 4);
381c2c66affSColin Finck 
382c2c66affSColin Finck     /* Apply the patch */
383c2c66affSColin Finck     *Patch = PtrToUlong(Interrupt);
384c2c66affSColin Finck 
385c2c66affSColin Finck     /* Disconnect it at first */
386c2c66affSColin Finck     Interrupt->Connected = FALSE;
387c2c66affSColin Finck }
388c2c66affSColin Finck 
389c2c66affSColin Finck /*
390c2c66affSColin Finck  * @implemented
391c2c66affSColin Finck  */
392c2c66affSColin Finck BOOLEAN
393c2c66affSColin Finck NTAPI
KeConnectInterrupt(IN PKINTERRUPT Interrupt)394c2c66affSColin Finck KeConnectInterrupt(IN PKINTERRUPT Interrupt)
395c2c66affSColin Finck {
396c2c66affSColin Finck     BOOLEAN Connected, Error, Status;
397c2c66affSColin Finck     KIRQL Irql, OldIrql;
398c2c66affSColin Finck     UCHAR Number;
399c2c66affSColin Finck     ULONG Vector;
400c2c66affSColin Finck     DISPATCH_INFO Dispatch;
401c2c66affSColin Finck 
402c2c66affSColin Finck     /* Get data from interrupt */
403c2c66affSColin Finck     Number = Interrupt->Number;
404c2c66affSColin Finck     Vector = Interrupt->Vector;
405c2c66affSColin Finck     Irql = Interrupt->Irql;
406c2c66affSColin Finck 
407c2c66affSColin Finck     /* Validate the settings */
408c2c66affSColin Finck     if ((Irql > HIGH_LEVEL) ||
409c2c66affSColin Finck         (Number >= KeNumberProcessors) ||
410c2c66affSColin Finck         (Interrupt->SynchronizeIrql < Irql) ||
411c2c66affSColin Finck         (Interrupt->FloatingSave))
412c2c66affSColin Finck     {
413c2c66affSColin Finck         return FALSE;
414c2c66affSColin Finck     }
415c2c66affSColin Finck 
416c2c66affSColin Finck     /* Set defaults */
417c2c66affSColin Finck     Connected = FALSE;
418c2c66affSColin Finck     Error = FALSE;
419c2c66affSColin Finck 
420c2c66affSColin Finck     /* Set the system affinity and acquire the dispatcher lock */
421c2c66affSColin Finck     KeSetSystemAffinityThread(1 << Number);
422c2c66affSColin Finck     OldIrql = KiAcquireDispatcherLock();
423c2c66affSColin Finck 
424c2c66affSColin Finck     /* Check if it's already been connected */
425c2c66affSColin Finck     if (!Interrupt->Connected)
426c2c66affSColin Finck     {
427c2c66affSColin Finck         /* Get vector dispatching information */
428c2c66affSColin Finck         KiGetVectorDispatch(Vector, &Dispatch);
429c2c66affSColin Finck 
430c2c66affSColin Finck         /* Check if the vector is already connected */
431c2c66affSColin Finck         if (Dispatch.Type == NoConnect)
432c2c66affSColin Finck         {
433c2c66affSColin Finck             /* Do the connection */
434c2c66affSColin Finck             Interrupt->Connected = Connected = TRUE;
435c2c66affSColin Finck 
436c2c66affSColin Finck             /* Initialize the list */
437c2c66affSColin Finck             InitializeListHead(&Interrupt->InterruptListEntry);
438c2c66affSColin Finck 
439c2c66affSColin Finck             /* Connect and enable the interrupt */
440c2c66affSColin Finck             KiConnectVectorToInterrupt(Interrupt, NormalConnect);
441c2c66affSColin Finck             Status = HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode);
442c2c66affSColin Finck             if (!Status) Error = TRUE;
443c2c66affSColin Finck         }
444c2c66affSColin Finck         else if ((Dispatch.Type != UnknownConnect) &&
445c2c66affSColin Finck                 (Interrupt->ShareVector) &&
446c2c66affSColin Finck                 (Dispatch.Interrupt->ShareVector) &&
447c2c66affSColin Finck                 (Dispatch.Interrupt->Mode == Interrupt->Mode))
448c2c66affSColin Finck         {
449c2c66affSColin Finck             /* The vector is shared and the interrupts are compatible */
450c2c66affSColin Finck             Interrupt->Connected = Connected = TRUE;
451c2c66affSColin Finck 
452c2c66affSColin Finck             /*
453c2c66affSColin Finck              * Verify the IRQL for chained connect,
454c2c66affSColin Finck              */
455c2c66affSColin Finck #if defined(CONFIG_SMP)
456c2c66affSColin Finck             ASSERT(Irql <= SYNCH_LEVEL);
457c2c66affSColin Finck #else
458c2c66affSColin Finck             ASSERT(Irql <= (IPI_LEVEL - 2));
459c2c66affSColin Finck #endif
460c2c66affSColin Finck 
461c2c66affSColin Finck             /* Check if this is the first chain */
462c2c66affSColin Finck             if (Dispatch.Type != ChainConnect)
463c2c66affSColin Finck             {
464c2c66affSColin Finck                 /* This is not supported */
465c2c66affSColin Finck                 ASSERT(Dispatch.Interrupt->Mode != Latched);
466c2c66affSColin Finck 
467c2c66affSColin Finck                 /* Setup the chainned handler */
468c2c66affSColin Finck                 KiConnectVectorToInterrupt(Dispatch.Interrupt, ChainConnect);
469c2c66affSColin Finck             }
470c2c66affSColin Finck 
471c2c66affSColin Finck             /* Insert into the interrupt list */
472c2c66affSColin Finck             InsertTailList(&Dispatch.Interrupt->InterruptListEntry,
473c2c66affSColin Finck                            &Interrupt->InterruptListEntry);
474c2c66affSColin Finck         }
475c2c66affSColin Finck     }
476c2c66affSColin Finck 
477c2c66affSColin Finck     /* Unlock the dispatcher and revert affinity */
478c2c66affSColin Finck     KiReleaseDispatcherLock(OldIrql);
479c2c66affSColin Finck     KeRevertToUserAffinityThread();
480c2c66affSColin Finck 
481c2c66affSColin Finck     /* Check if we failed while trying to connect */
482c2c66affSColin Finck     if ((Connected) && (Error))
483c2c66affSColin Finck     {
484c2c66affSColin Finck         DPRINT1("HalEnableSystemInterrupt failed\n");
485c2c66affSColin Finck         KeDisconnectInterrupt(Interrupt);
486c2c66affSColin Finck         Connected = FALSE;
487c2c66affSColin Finck     }
488c2c66affSColin Finck 
489c2c66affSColin Finck     /* Return to caller */
490c2c66affSColin Finck     return Connected;
491c2c66affSColin Finck }
492c2c66affSColin Finck 
493c2c66affSColin Finck /*
494c2c66affSColin Finck  * @implemented
495c2c66affSColin Finck  */
496c2c66affSColin Finck BOOLEAN
497c2c66affSColin Finck NTAPI
KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)498c2c66affSColin Finck KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)
499c2c66affSColin Finck {
500c2c66affSColin Finck     KIRQL OldIrql, Irql;
501c2c66affSColin Finck     ULONG Vector;
502c2c66affSColin Finck     DISPATCH_INFO Dispatch;
503c2c66affSColin Finck     PKINTERRUPT NextInterrupt;
504c2c66affSColin Finck     BOOLEAN State;
505c2c66affSColin Finck 
506c2c66affSColin Finck     /* Set the affinity */
507c2c66affSColin Finck     KeSetSystemAffinityThread(1 << Interrupt->Number);
508c2c66affSColin Finck 
509c2c66affSColin Finck     /* Lock the dispatcher */
510c2c66affSColin Finck     OldIrql = KiAcquireDispatcherLock();
511c2c66affSColin Finck 
512c2c66affSColin Finck     /* Check if it's actually connected */
513c2c66affSColin Finck     State = Interrupt->Connected;
514c2c66affSColin Finck     if (State)
515c2c66affSColin Finck     {
516c2c66affSColin Finck         /* Get the vector and IRQL */
517c2c66affSColin Finck         Irql = Interrupt->Irql;
518c2c66affSColin Finck         Vector = Interrupt->Vector;
519c2c66affSColin Finck 
520c2c66affSColin Finck         /* Get vector dispatch data */
521c2c66affSColin Finck         KiGetVectorDispatch(Vector, &Dispatch);
522c2c66affSColin Finck 
523c2c66affSColin Finck         /* Check if it was chained */
524c2c66affSColin Finck         if (Dispatch.Type == ChainConnect)
525c2c66affSColin Finck         {
526c2c66affSColin Finck             /* Check if the top-level interrupt is being removed */
527c2c66affSColin Finck #if defined(CONFIG_SMP)
528c2c66affSColin Finck             ASSERT(Irql <= SYNCH_LEVEL);
529c2c66affSColin Finck #else
530c2c66affSColin Finck             ASSERT(Irql <= (IPI_LEVEL - 2));
531c2c66affSColin Finck #endif
532c2c66affSColin Finck             if (Interrupt == Dispatch.Interrupt)
533c2c66affSColin Finck             {
534c2c66affSColin Finck                 /* Get the next one */
535c2c66affSColin Finck                 Dispatch.Interrupt = CONTAINING_RECORD(Dispatch.Interrupt->
536c2c66affSColin Finck                                                        InterruptListEntry.Flink,
537c2c66affSColin Finck                                                        KINTERRUPT,
538c2c66affSColin Finck                                                        InterruptListEntry);
539c2c66affSColin Finck 
540c2c66affSColin Finck                 /* Reconnect it */
541c2c66affSColin Finck                 KiConnectVectorToInterrupt(Dispatch.Interrupt, ChainConnect);
542c2c66affSColin Finck             }
543c2c66affSColin Finck 
544c2c66affSColin Finck             /* Remove it */
545c2c66affSColin Finck             RemoveEntryList(&Interrupt->InterruptListEntry);
546c2c66affSColin Finck 
547c2c66affSColin Finck             /* Get the next one */
548c2c66affSColin Finck             NextInterrupt = CONTAINING_RECORD(Dispatch.Interrupt->
549c2c66affSColin Finck                                               InterruptListEntry.Flink,
550c2c66affSColin Finck                                               KINTERRUPT,
551c2c66affSColin Finck                                               InterruptListEntry);
552c2c66affSColin Finck 
553c2c66affSColin Finck             /* Check if this is the only one left */
554c2c66affSColin Finck             if (Dispatch.Interrupt == NextInterrupt)
555c2c66affSColin Finck             {
556c2c66affSColin Finck                 /* Connect it in non-chained mode */
557c2c66affSColin Finck                 KiConnectVectorToInterrupt(Dispatch.Interrupt, NormalConnect);
558c2c66affSColin Finck             }
559c2c66affSColin Finck         }
560c2c66affSColin Finck         else
561c2c66affSColin Finck         {
562c2c66affSColin Finck             /* Only one left, disable and remove it */
563c2c66affSColin Finck             HalDisableSystemInterrupt(Interrupt->Vector, Irql);
564c2c66affSColin Finck             KiConnectVectorToInterrupt(Interrupt, NoConnect);
565c2c66affSColin Finck         }
566c2c66affSColin Finck 
567c2c66affSColin Finck         /* Disconnect it */
568c2c66affSColin Finck         Interrupt->Connected = FALSE;
569c2c66affSColin Finck     }
570c2c66affSColin Finck 
571c2c66affSColin Finck     /* Unlock the dispatcher and revert affinity */
572c2c66affSColin Finck     KiReleaseDispatcherLock(OldIrql);
573c2c66affSColin Finck     KeRevertToUserAffinityThread();
574c2c66affSColin Finck 
575c2c66affSColin Finck     /* Return to caller */
576c2c66affSColin Finck     return State;
577c2c66affSColin Finck }
578c2c66affSColin Finck 
579c2c66affSColin Finck /*
580c2c66affSColin Finck  * @implemented
581c2c66affSColin Finck  */
582c2c66affSColin Finck BOOLEAN
583c2c66affSColin Finck NTAPI
KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt,IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,IN PVOID SynchronizeContext OPTIONAL)584c2c66affSColin Finck KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt,
585c2c66affSColin Finck                        IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
586c2c66affSColin Finck                        IN PVOID SynchronizeContext OPTIONAL)
587c2c66affSColin Finck {
588c2c66affSColin Finck     BOOLEAN Success;
589c2c66affSColin Finck     KIRQL OldIrql;
590c2c66affSColin Finck 
591c2c66affSColin Finck     /* Raise IRQL */
592c2c66affSColin Finck     KeRaiseIrql(Interrupt->SynchronizeIrql,
593c2c66affSColin Finck                 &OldIrql);
594c2c66affSColin Finck 
595c2c66affSColin Finck     /* Acquire interrupt spinlock */
596c2c66affSColin Finck     KeAcquireSpinLockAtDpcLevel(Interrupt->ActualLock);
597c2c66affSColin Finck 
598c2c66affSColin Finck     /* Call the routine */
599c2c66affSColin Finck     Success = SynchronizeRoutine(SynchronizeContext);
600c2c66affSColin Finck 
601c2c66affSColin Finck     /* Release lock */
602c2c66affSColin Finck     KeReleaseSpinLockFromDpcLevel(Interrupt->ActualLock);
603c2c66affSColin Finck 
604c2c66affSColin Finck     /* Lower IRQL */
605c2c66affSColin Finck     KeLowerIrql(OldIrql);
606c2c66affSColin Finck 
607c2c66affSColin Finck     /* Return status */
608c2c66affSColin Finck     return Success;
609c2c66affSColin Finck }
610c2c66affSColin Finck 
611c2c66affSColin Finck /* EOF */
612