ReactOS  0.4.15-dev-5499-g1341c38
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 
22 void KiInterruptDispatch(void);
23 
24 
25 /* FUNCTIONS ****************************************************************/
26 
27 VOID
28 NTAPI
34  IN ULONG Vector,
35  IN KIRQL Irql,
39  IN CHAR ProcessorNumber,
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,
74  sizeof(Interrupt->DispatchCode));
75 
76  Interrupt->DispatchAddress = 0;
77 }
78 
79 BOOLEAN
80 NTAPI
82 {
83  PVOID CurrentHandler;
84  PKINTERRUPT ConnectedInterrupt;
85  KIRQL OldIrql;
86 
90  ASSERT(Interrupt->Irql <= HIGH_LEVEL);
91  ASSERT(Interrupt->SynchronizeIrql >= Interrupt->Irql);
92  ASSERT(Interrupt->Irql == (Interrupt->Vector >> 4));
93 
94  /* Check if its already connected */
95  if (Interrupt->Connected) return TRUE;
96 
97  /* Set the system affinity and acquire the dispatcher lock */
100 
101  /* Query the current handler */
102  CurrentHandler = KeQueryInterruptHandler(Interrupt->Vector);
103 
104  /* Check if the vector is unused */
105  if ((CurrentHandler >= (PVOID)KiUnexpectedRange) &&
106  (CurrentHandler <= (PVOID)KiUnexpectedRangeEnd))
107  {
108  /* Initialize the list for chained interrupts */
109  InitializeListHead(&Interrupt->InterruptListEntry);
110 
111  /* Set normal dispatch address */
112  Interrupt->DispatchAddress = KiInterruptDispatch;
113 
114  /* Set the new handler */
116  Interrupt->DispatchCode);
117 
118  /* Enable the interrupt */
119  if (!HalEnableSystemInterrupt(Interrupt->Vector,
120  Interrupt->Irql,
121  Interrupt->Mode))
122  {
123  /* Didn't work, restore old handler */
124  DPRINT1("HalEnableSystemInterrupt failed\n");
125  KeRegisterInterruptHandler(Interrupt->Vector, CurrentHandler);
126  goto Cleanup;
127  }
128  }
129  else
130  {
131  /* Get the connected interrupt */
132  ConnectedInterrupt = CONTAINING_RECORD(CurrentHandler, KINTERRUPT, DispatchCode);
133 
134  /* Check if sharing is ok */
135  if ((Interrupt->ShareVector == 0) ||
136  (ConnectedInterrupt->ShareVector == 0) ||
137  (Interrupt->Mode != ConnectedInterrupt->Mode))
138  {
139  goto Cleanup;
140  }
141 
142  /* Insert the new interrupt into the connected interrupt's list */
143  InsertTailList(&ConnectedInterrupt->InterruptListEntry,
144  &Interrupt->InterruptListEntry);
145  }
146 
147  /* Mark as connected */
148  Interrupt->Connected = TRUE;
149 
150 Cleanup:
151  /* Release the dispatcher lock and restore the thread affinity */
154  return Interrupt->Connected;
155 }
156 
157 BOOLEAN
158 NTAPI
160 {
161  KIRQL OldIrql;
162  PVOID VectorHandler, UnexpectedHandler;
163  PKINTERRUPT VectorFirstInterrupt, NextInterrupt;
164  PLIST_ENTRY HandlerHead;
165 
166  /* Set the system affinity and acquire the dispatcher lock */
169 
170  /* Check if the interrupt was connected - otherwise there's nothing to do */
171  if (Interrupt->Connected)
172  {
173  /* Get the handler for this interrupt vector */
174  VectorHandler = KeQueryInterruptHandler(Interrupt->Vector);
175 
176  /* Get the first interrupt for this handler */
177  VectorFirstInterrupt = CONTAINING_RECORD(VectorHandler, KINTERRUPT, DispatchCode);
178 
179  /* The first interrupt list entry is the interrupt list head */
180  HandlerHead = &VectorFirstInterrupt->InterruptListEntry;
181 
182  /* If the list is empty, this is the only interrupt for this vector */
183  if (IsListEmpty(HandlerHead))
184  {
185  /* If the list is empty, and the head is not from this interrupt,
186  * this interrupt is somehow incorrectly connected */
187  ASSERT(VectorFirstInterrupt == Interrupt);
188 
189  UnexpectedHandler = &KiUnexpectedRange[Interrupt->Vector]._Op_push;
190 
191  /* This is the only interrupt, the handler can be disconnected */
193  KeRegisterInterruptHandler(Interrupt->Vector, UnexpectedHandler);
194  }
195  /* If the interrupt to be disconnected is the list head, but some others follow */
196  else if (VectorFirstInterrupt == Interrupt)
197  {
198  /* Relocate the head to the next element */
199  HandlerHead = HandlerHead->Flink;
200  RemoveTailList(HandlerHead);
201 
202  /* Get the next interrupt from the list head */
203  NextInterrupt = CONTAINING_RECORD(HandlerHead,
204  KINTERRUPT,
205  InterruptListEntry);
206 
207  /* Set the next interrupt as the handler for this vector */
209  NextInterrupt->DispatchCode);
210  }
211  /* If the interrupt to be disconnected is not the list head */
212  else
213  {
214  /* Remove the to be disconnected interrupt from the interrupt list */
215  RemoveEntryList(&Interrupt->InterruptListEntry);
216  }
217 
218  /* Mark as not connected */
219  Interrupt->Connected = FALSE;
220  }
221 
222  /* Release the dispatcher lock and restore the thread affinity */
225 
226  return TRUE;
227 }
228 
229 BOOLEAN
230 NTAPI
234 {
236  KIRQL OldIrql;
237 
238  /* Raise IRQL */
239  OldIrql = KfRaiseIrql(Interrupt->SynchronizeIrql);
240 
241  /* Acquire interrupt spinlock */
243 
244  /* Call the routine */
246 
247  /* Release lock */
249 
250  /* Lower IRQL */
252 
253  /* Return status */
254  return Success;
255 }
#define IN
Definition: typedefs.h:39
BOOLEAN NTAPI HalEnableSystemInterrupt(IN ULONG Vector, IN KIRQL Irql, IN KINTERRUPT_MODE InterruptMode)
Definition: pic.c:295
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID _In_opt_ PKSPIN_LOCK _In_ ULONG _In_ KIRQL _In_ KIRQL _In_ KINTERRUPT_MODE InterruptMode
Definition: iofuncs.h:800
UCHAR KiInterruptDispatchTemplate[16]
#define TRUE
Definition: types.h:120
_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:800
VOID NTAPI KeRevertToUserAffinityThread(VOID)
Definition: thrdobj.c:1030
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_INTERRUPT_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFINTERRUPT * Interrupt
Definition: wdfinterrupt.h:372
KI_INTERRUPT_DISPATCH_ENTRY KiUnexpectedRangeEnd[]
char CHAR
Definition: xmlstorage.h:175
FORCEINLINE PLIST_ENTRY RemoveTailList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:154
VOID NTAPI KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:198
#define PRIMARY_VECTOR_BASE
Definition: halp.h:16
KSPIN_LOCK * PKSPIN_LOCK
Definition: env_spec_w32.h:73
#define InsertTailList(ListHead, Entry)
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
_Out_ PKIRQL Irql
Definition: csq.h:179
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
FORCEINLINE PVOID KeQueryInterruptHandler(IN ULONG Vector)
Definition: ke.h:327
VOID NTAPI KeSetSystemAffinityThread(IN KAFFINITY Affinity)
Definition: thrdobj.c:1116
KINTERRUPT_MODE Mode
Definition: ketypes.h:895
VOID NTAPI HalDisableSystemInterrupt(IN ULONG Vector, IN KIRQL Irql)
Definition: pic.c:309
KSERVICE_ROUTINE * PKSERVICE_ROUTINE
Definition: ketypes.h:500
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
UCHAR KIRQL
Definition: env_spec_w32.h:591
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFSPINLOCK * SpinLock
Definition: wdfsync.h:225
FORCEINLINE VOID KeInitializeSpinLock(_Out_ PKSPIN_LOCK SpinLock)
Definition: kefuncs.h:240
unsigned char BOOLEAN
enum _KINTERRUPT_MODE KINTERRUPT_MODE
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID _In_opt_ PKSPIN_LOCK _In_ ULONG _In_ KIRQL _In_ KIRQL SynchronizeIrql
Definition: iofuncs.h:800
KSYNCHRONIZE_ROUTINE * PKSYNCHRONIZE_ROUTINE
Definition: ketypes.h:863
UCHAR _Op_push
Definition: ke.h:105
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define ULL(a, b)
Definition: format_msg.c:27
KIRQL FASTCALL KfRaiseIrql(IN KIRQL NewIrql)
Definition: pic.c:187
LIST_ENTRY InterruptListEntry
Definition: ketypes.h:877
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
_In_ PKSYNCHRONIZE_ROUTINE SynchronizeRoutine
Definition: kefuncs.h:538
#define ASSERT(a)
Definition: mode.c:44
VOID NTAPI KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:221
BOOLEAN ShareVector
Definition: ketypes.h:894
BOOLEAN NTAPI KeConnectInterrupt(IN PKINTERRUPT Interrupt)
Definition: interrupt.c:81
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID ServiceContext
Definition: iofuncs.h:800
unsigned char UCHAR
Definition: xmlstorage.h:181
Definition: ke.h:102
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:792
_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:800
Definition: typedefs.h:119
static const WCHAR Cleanup[]
Definition: register.c:80
BOOLEAN NTAPI KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)
Definition: interrupt.c:159
KI_INTERRUPT_DISPATCH_ENTRY KiUnexpectedRange[256]
CCHAR KeNumberProcessors
Definition: krnlinit.c:35
FORCEINLINE VOID KeRegisterInterruptHandler(IN ULONG Vector, IN PVOID Handler)
Definition: ke.h:301
ULONG DispatchCode[DISPATCH_LENGTH]
Definition: ketypes.h:908
_In_ PKSYNCHRONIZE_ROUTINE _In_opt_ __drv_aliasesMem PVOID SynchronizeContext
Definition: kefuncs.h:538
#define HIGH_LEVEL
Definition: env_spec_w32.h:703
FORCEINLINE VOID KiReleaseDispatcherLock(IN KIRQL OldIrql)
Definition: ke_x.h:157
FORCEINLINE KIRQL KiAcquireDispatcherLock(VOID)
Definition: ke_x.h:149
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID _In_opt_ PKSPIN_LOCK _In_ ULONG Vector
Definition: iofuncs.h:800
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define NULL
Definition: types.h:112
#define DPRINT1
Definition: precomp.h:8
#define OUT
Definition: typedefs.h:40
struct _KINTERRUPT KINTERRUPT
unsigned int ULONG
Definition: retypes.h:1
BOOLEAN NTAPI KeSynchronizeExecution(IN OUT PKINTERRUPT Interrupt, IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine, IN PVOID SynchronizeContext OPTIONAL)
Definition: interrupt.c:231
#define RtlCopyMemory(Destination, Source, Length)
Definition: typedefs.h:263
VOID NTAPI KeLowerIrql(KIRQL NewIrql)
Definition: spinlock.c:39
void KiInterruptDispatch(void)
#define MAXIMUM_IDTVECTOR
Definition: asm.h:280
_In_ PKSERVICE_ROUTINE ServiceRoutine
Definition: iofuncs.h:800
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68