xref: /reactos/ntoskrnl/ke/amd64/interrupt.c (revision 40462c92)
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 
85     ASSERT(Interrupt->Vector <= MAXIMUM_IDTVECTOR);
86     ASSERT(Interrupt->Number < KeNumberProcessors);
87     ASSERT(Interrupt->Irql <= HIGH_LEVEL);
88 
89     /* Check if its already connected */
90     if (Interrupt->Connected) return TRUE;
91 
92     /* Query the current handler */
93     CurrentHandler = KeQueryInterruptHandler(Interrupt->Vector);
94 
95     /* Check if the vector is already unused */
96     if ((CurrentHandler >= (PVOID)KiUnexpectedRange) &&
97         (CurrentHandler <= (PVOID)KiUnexpectedRangeEnd))
98     {
99         /* Initialize the list for chained interrupts */
100         InitializeListHead(&Interrupt->InterruptListEntry);
101 
102         /* Set normal dispatch address */
103         Interrupt->DispatchAddress = KiInterruptDispatch;
104 
105         /* Set the new handler */
106         KeRegisterInterruptHandler(Interrupt->Vector,
107                                    Interrupt->DispatchCode);
108 
109         if (!HalEnableSystemInterrupt(Interrupt->Vector,
110                                       Interrupt->Irql,
111                                       Interrupt->Mode))
112         {
113             /* Didn't work, restore old handler */
114             DPRINT1("HalEnableSystemInterrupt failed\n");
115             KeRegisterInterruptHandler(Interrupt->Vector, CurrentHandler);
116             return FALSE;
117         }
118 
119         /* Mark as connected */
120         Interrupt->Connected = TRUE;
121     }
122     else
123     {
124         // later
125         __debugbreak();
126     }
127 
128     return TRUE;
129 }
130 
131 BOOLEAN
132 NTAPI
133 KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)
134 {
135     UNIMPLEMENTED;
136     __debugbreak();
137     return FALSE;
138 }
139 
140 BOOLEAN
141 NTAPI
142 KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt,
143                        IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
144                        IN PVOID SynchronizeContext OPTIONAL)
145 {
146     BOOLEAN Success;
147     KIRQL OldIrql;
148 
149     /* Raise IRQL */
150     OldIrql = KfRaiseIrql(Interrupt->SynchronizeIrql);
151 
152     /* Acquire interrupt spinlock */
153     KeAcquireSpinLockAtDpcLevel(Interrupt->ActualLock);
154 
155     /* Call the routine */
156     Success = SynchronizeRoutine(SynchronizeContext);
157 
158     /* Release lock */
159     KeReleaseSpinLockFromDpcLevel(Interrupt->ActualLock);
160 
161     /* Lower IRQL */
162     KeLowerIrql(OldIrql);
163 
164     /* Return status */
165     return Success;
166 }
167