ReactOS 0.4.16-dev-334-g4d9f67c
interrupt.c
Go to the documentation of this file.
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
23
24
25/* FUNCTIONS ****************************************************************/
26
27VOID
39 IN CHAR ProcessorNumber,
41{
42
43 /* Initialize the header */
45 Interrupt->Size = sizeof(KINTERRUPT);
46
47 /* If no Spinlock is given, use the internal */
48 if (!SpinLock) SpinLock = &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;
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,
74 sizeof(Interrupt->DispatchCode));
75
76 Interrupt->DispatchAddress = 0;
77}
78
82{
83 PVOID CurrentHandler;
84 PKINTERRUPT ConnectedInterrupt;
86
87 /* Validate the vector */
88 if ((Interrupt->Vector < PRIMARY_VECTOR_BASE) ||
89 (Interrupt->Vector > MAXIMUM_IDTVECTOR))
90 {
91 DPRINT1("Invalid interrupt vector: %lu\n", Interrupt->Vector);
92 return FALSE;
93 }
94
96 ASSERT(Interrupt->Irql <= HIGH_LEVEL);
97 ASSERT(Interrupt->SynchronizeIrql >= Interrupt->Irql);
98 ASSERT(Interrupt->Irql == (Interrupt->Vector >> 4));
99
100 /* Check if its already connected */
101 if (Interrupt->Connected) return TRUE;
102
103 /* Set the system affinity and acquire the dispatcher lock */
104 KeSetSystemAffinityThread(1ULL << Interrupt->Number);
106
107 /* Query the current handler */
108 CurrentHandler = KeQueryInterruptHandler(Interrupt->Vector);
109
110 /* Check if the vector is unused */
111 if ((CurrentHandler >= (PVOID)KiUnexpectedRange) &&
112 (CurrentHandler <= (PVOID)KiUnexpectedRangeEnd))
113 {
114 /* Initialize the list for chained interrupts */
115 InitializeListHead(&Interrupt->InterruptListEntry);
116
117 /* Set normal dispatch address */
118 Interrupt->DispatchAddress = KiInterruptDispatch;
119
120 /* Set the new handler */
122 Interrupt->DispatchCode);
123
124 /* Enable the interrupt */
126 Interrupt->Irql,
127 Interrupt->Mode))
128 {
129 /* Didn't work, restore old handler */
130 DPRINT1("HalEnableSystemInterrupt failed\n");
131 KeRegisterInterruptHandler(Interrupt->Vector, CurrentHandler);
132 goto Cleanup;
133 }
134 }
135 else
136 {
137 /* Get the connected interrupt */
138 ConnectedInterrupt = CONTAINING_RECORD(CurrentHandler, KINTERRUPT, DispatchCode);
139
140 /* Check if sharing is ok */
141 if ((Interrupt->ShareVector == 0) ||
142 (ConnectedInterrupt->ShareVector == 0) ||
143 (Interrupt->Mode != ConnectedInterrupt->Mode))
144 {
145 goto Cleanup;
146 }
147
148 /* Insert the new interrupt into the connected interrupt's list */
149 InsertTailList(&ConnectedInterrupt->InterruptListEntry,
150 &Interrupt->InterruptListEntry);
151 }
152
153 /* Mark as connected */
154 Interrupt->Connected = TRUE;
155
156Cleanup:
157 /* Release the dispatcher lock and restore the thread affinity */
160 return Interrupt->Connected;
161}
162
164NTAPI
166{
168 PVOID VectorHandler, UnexpectedHandler;
169 PKINTERRUPT VectorFirstInterrupt, NextInterrupt;
170 PLIST_ENTRY HandlerHead;
171
172 /* Set the system affinity and acquire the dispatcher lock */
173 KeSetSystemAffinityThread(1ULL << Interrupt->Number);
175
176 /* Check if the interrupt was connected - otherwise there's nothing to do */
177 if (Interrupt->Connected)
178 {
179 /* Get the handler for this interrupt vector */
180 VectorHandler = KeQueryInterruptHandler(Interrupt->Vector);
181
182 /* Get the first interrupt for this handler */
183 VectorFirstInterrupt = CONTAINING_RECORD(VectorHandler, KINTERRUPT, DispatchCode);
184
185 /* The first interrupt list entry is the interrupt list head */
186 HandlerHead = &VectorFirstInterrupt->InterruptListEntry;
187
188 /* If the list is empty, this is the only interrupt for this vector */
189 if (IsListEmpty(HandlerHead))
190 {
191 /* If the list is empty, and the head is not from this interrupt,
192 * this interrupt is somehow incorrectly connected */
193 ASSERT(VectorFirstInterrupt == Interrupt);
194
195 UnexpectedHandler = &KiUnexpectedRange[Interrupt->Vector]._Op_push;
196
197 /* This is the only interrupt, the handler can be disconnected */
199 KeRegisterInterruptHandler(Interrupt->Vector, UnexpectedHandler);
200 }
201 /* If the interrupt to be disconnected is the list head, but some others follow */
202 else if (VectorFirstInterrupt == Interrupt)
203 {
204 /* Relocate the head to the next element */
205 HandlerHead = HandlerHead->Flink;
206 RemoveTailList(HandlerHead);
207
208 /* Get the next interrupt from the list head */
209 NextInterrupt = CONTAINING_RECORD(HandlerHead,
211 InterruptListEntry);
212
213 /* Set the next interrupt as the handler for this vector */
215 NextInterrupt->DispatchCode);
216 }
217 /* If the interrupt to be disconnected is not the list head */
218 else
219 {
220 /* Remove the to be disconnected interrupt from the interrupt list */
221 RemoveEntryList(&Interrupt->InterruptListEntry);
222 }
223
224 /* Mark as not connected */
225 Interrupt->Connected = FALSE;
226 }
227
228 /* Release the dispatcher lock and restore the thread affinity */
231
232 return TRUE;
233}
234
236NTAPI
240{
243
244 /* Raise IRQL */
245 OldIrql = KfRaiseIrql(Interrupt->SynchronizeIrql);
246
247 /* Acquire interrupt spinlock */
249
250 /* Call the routine */
252
253 /* Release lock */
255
256 /* Lower IRQL */
258
259 /* Return status */
260 return Success;
261}
static KSYNCHRONIZE_ROUTINE SynchronizeRoutine
Definition: IoInterrupt.c:30
unsigned char BOOLEAN
#define DPRINT1
Definition: precomp.h:8
_Out_ PKIRQL Irql
Definition: csq.h:179
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
static const WCHAR Cleanup[]
Definition: register.c:80
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define HIGH_LEVEL
Definition: env_spec_w32.h:703
KSPIN_LOCK * PKSPIN_LOCK
Definition: env_spec_w32.h:73
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define RemoveTailList(ListHead)
Definition: env_spec_w32.h:975
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define KeInitializeSpinLock(sl)
Definition: env_spec_w32.h:604
@ Success
Definition: eventcreate.c:712
BOOLEAN NTAPI HalEnableSystemInterrupt(IN ULONG Vector, IN KIRQL Irql, IN KINTERRUPT_MODE InterruptMode)
Definition: pic.c:295
VOID NTAPI HalDisableSystemInterrupt(IN ULONG Vector, IN KIRQL Irql)
Definition: pic.c:309
KIRQL FASTCALL KfRaiseIrql(IN KIRQL NewIrql)
Definition: pic.c:187
#define PRIMARY_VECTOR_BASE
Definition: halp.h:16
FORCEINLINE VOID KiReleaseDispatcherLock(IN KIRQL OldIrql)
Definition: ke_x.h:157
FORCEINLINE KIRQL KiAcquireDispatcherLock(VOID)
Definition: ke_x.h:149
CCHAR KeNumberProcessors
Definition: krnlinit.c:35
#define ASSERT(a)
Definition: mode.c:44
#define MAXIMUM_IDTVECTOR
Definition: asm.h:280
struct _KINTERRUPT KINTERRUPT
@ InterruptObject
Definition: ketypes.h:428
FORCEINLINE PVOID KeQueryInterruptHandler(IN ULONG Vector)
Definition: ke.h:327
FORCEINLINE VOID KeRegisterInterruptHandler(IN ULONG Vector, IN PVOID Handler)
Definition: ke.h:301
KI_INTERRUPT_DISPATCH_ENTRY KiUnexpectedRange[256]
BOOLEAN NTAPI KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)
Definition: interrupt.c:165
BOOLEAN NTAPI KeConnectInterrupt(IN PKINTERRUPT Interrupt)
Definition: interrupt.c:81
void KiInterruptDispatch(void)
KI_INTERRUPT_DISPATCH_ENTRY KiUnexpectedRangeEnd[]
UCHAR KiInterruptDispatchTemplate[16]
VOID 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)
Definition: interrupt.c:29
BOOLEAN NTAPI KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt, IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine, IN PVOID SynchronizeContext OPTIONAL)
Definition: interrupt.c:237
enum _KINTERRUPT_MODE KINTERRUPT_MODE
#define KeAcquireSpinLockAtDpcLevel(SpinLock)
Definition: ke.h:125
#define KeReleaseSpinLockFromDpcLevel(SpinLock)
Definition: ke.h:135
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
ULONG DispatchCode[DISPATCH_LENGTH]
Definition: ketypes.h:968
KINTERRUPT_MODE Mode
Definition: ketypes.h:955
BOOLEAN ShareVector
Definition: ketypes.h:954
LIST_ENTRY InterruptListEntry
Definition: ketypes.h:937
Definition: ke.h:103
UCHAR _Op_push
Definition: ke.h:105
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
VOID NTAPI KeSetSystemAffinityThread(IN KAFFINITY Affinity)
Definition: thrdobj.c:1107
VOID NTAPI KeRevertToUserAffinityThread(VOID)
Definition: thrdobj.c:1021
#define NTAPI
Definition: typedefs.h:36
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
#define IN
Definition: typedefs.h:39
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_INTERRUPT_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFINTERRUPT * Interrupt
Definition: wdfinterrupt.h:379
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFSPINLOCK * SpinLock
Definition: wdfsync.h:228
_In_ PKSERVICE_ROUTINE ServiceRoutine
Definition: iofuncs.h:800
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID _In_opt_ PKSPIN_LOCK _In_ ULONG _In_ KIRQL _In_ KIRQL _In_ KINTERRUPT_MODE InterruptMode
Definition: iofuncs.h:806
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID _In_opt_ PKSPIN_LOCK _In_ ULONG _In_ KIRQL _In_ KIRQL SynchronizeIrql
Definition: iofuncs.h:805
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID _In_opt_ PKSPIN_LOCK _In_ ULONG _In_ KIRQL _In_ KIRQL _In_ KINTERRUPT_MODE _In_ BOOLEAN _In_ KAFFINITY _In_ BOOLEAN FloatingSave
Definition: iofuncs.h:809
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID _In_opt_ PKSPIN_LOCK _In_ ULONG _In_ KIRQL _In_ KIRQL _In_ KINTERRUPT_MODE _In_ BOOLEAN ShareVector
Definition: iofuncs.h:807
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID ServiceContext
Definition: iofuncs.h:801
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
_In_ PKSYNCHRONIZE_ROUTINE _In_opt_ __drv_aliasesMem PVOID SynchronizeContext
Definition: kefuncs.h:525
KSERVICE_ROUTINE * PKSERVICE_ROUTINE
Definition: ketypes.h:512
KSYNCHRONIZE_ROUTINE * PKSYNCHRONIZE_ROUTINE
Definition: ketypes.h:875
unsigned char UCHAR
Definition: xmlstorage.h:181
char CHAR
Definition: xmlstorage.h:175