3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/i386/irq.c
6 * PURPOSE: IRQ handling
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
13 * NOTE: In general the PIC interrupt priority facilities are used to
14 * preserve the NT IRQL semantics, global interrupt disables are only used
15 * to keep the PIC in a consistent state
19 /* INCLUDES ****************************************************************/
22 #include <../hal/halx86/include/halirq.h>
25 #include <internal/debug.h>
27 /* GLOBALS *****************************************************************/
29 /* Interrupt handler list */
33 #define INT_NAME2(intnum) KiUnexpectedInterrupt##intnum
35 #define BUILD_INTERRUPT_HANDLER(intnum) \
36 VOID INT_NAME2(intnum)(VOID);
39 BUILD_INTERRUPT_HANDLER(x##y)
42 D(x,0) D(x,1) D(x,2) D(x,3) \
43 D(x,4) D(x,5) D(x,6) D(x,7) \
44 D(x,8) D(x,9) D(x,A) D(x,B) \
45 D(x,C) D(x,D) D(x,E) D(x,F)
47 D16(3) D16(4) D16(5) D16(6)
48 D16(7) D16(8) D16(9) D16(A
)
49 D16(B
) D16(C
) D16(D
) D16(E
)
53 (ULONG)& INT_NAME2(x##y)
56 L(x,0), L(x,1), L(x,2), L(x,3), \
57 L(x,4), L(x,5), L(x,6), L(x,7), \
58 L(x,8), L(x,9), L(x,A), L(x,B), \
59 L(x,C), L(x,D), L(x,E), L(x,F)
61 static ULONG irq_handler
[ROUND_UP(NR_IRQS
, 16)] = {
62 L16(3), L16(4), L16(5), L16(6),
63 L16(7), L16(8), L16(9), L16(A
),
64 L16(B
), L16(C
), L16(D
), L16(E
)
72 #else /* CONFIG_SMP */
74 void irq_handler_0(void);
75 void irq_handler_1(void);
76 void irq_handler_2(void);
77 void irq_handler_3(void);
78 void irq_handler_4(void);
79 void irq_handler_5(void);
80 void irq_handler_6(void);
81 void irq_handler_7(void);
82 void irq_handler_8(void);
83 void irq_handler_9(void);
84 void irq_handler_10(void);
85 void irq_handler_11(void);
86 void irq_handler_12(void);
87 void irq_handler_13(void);
88 void irq_handler_14(void);
89 void irq_handler_15(void);
91 static unsigned int irq_handler
[NR_IRQS
]=
103 (int)&irq_handler_10
,
104 (int)&irq_handler_11
,
105 (int)&irq_handler_12
,
106 (int)&irq_handler_13
,
107 (int)&irq_handler_14
,
108 (int)&irq_handler_15
,
111 #endif /* CONFIG_SMP */
114 * PURPOSE: Object describing each isr
115 * NOTE: The data in this table is only modified at passsive level but can
116 * be accessed at any irq level.
125 ISR_TABLE
, *PISR_TABLE
;
128 static ISR_TABLE IsrTable
[NR_IRQS
][MAXIMUM_PROCESSORS
];
130 static ISR_TABLE IsrTable
[NR_IRQS
][1];
133 #define TAG_ISR_LOCK TAG('I', 'S', 'R', 'L')
135 /* FUNCTIONS ****************************************************************/
137 #define PRESENT (0x8000)
138 #define I486_INTERRUPT_GATE (0xe00)
143 KeInitInterrupts (VOID
)
149 * Setup the IDT entries to point to the interrupt handlers
151 for (i
=0;i
<NR_IRQS
;i
++)
153 KiIdt
[IRQ_BASE
+i
].a
=(irq_handler
[i
]&0xffff)+(KGDT_R0_CODE
<<16);
154 KiIdt
[IRQ_BASE
+i
].b
=(irq_handler
[i
]&0xffff0000)+PRESENT
+
157 for (j
= 0; j
< MAXIMUM_PROCESSORS
; j
++)
162 InitializeListHead(&IsrTable
[i
][j
].ListHead
);
163 KeInitializeSpinLock(&IsrTable
[i
][j
].Lock
);
164 IsrTable
[i
][j
].Count
= 0;
170 KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame
,
171 PKTRAP_FRAME TrapFrame
)
173 TrapFrame
->Gs
= (USHORT
)IrqTrapFrame
->Gs
;
174 TrapFrame
->Fs
= (USHORT
)IrqTrapFrame
->Fs
;
175 TrapFrame
->Es
= (USHORT
)IrqTrapFrame
->Es
;
176 TrapFrame
->Ds
= (USHORT
)IrqTrapFrame
->Ds
;
177 TrapFrame
->Eax
= IrqTrapFrame
->Eax
;
178 TrapFrame
->Ecx
= IrqTrapFrame
->Ecx
;
179 TrapFrame
->Edx
= IrqTrapFrame
->Edx
;
180 TrapFrame
->Ebx
= IrqTrapFrame
->Ebx
;
181 TrapFrame
->Esp
= IrqTrapFrame
->Esp
;
182 TrapFrame
->Ebp
= IrqTrapFrame
->Ebp
;
183 TrapFrame
->Esi
= IrqTrapFrame
->Esi
;
184 TrapFrame
->Edi
= IrqTrapFrame
->Edi
;
185 TrapFrame
->Eip
= IrqTrapFrame
->Eip
;
186 TrapFrame
->Cs
= IrqTrapFrame
->Cs
;
187 TrapFrame
->Eflags
= IrqTrapFrame
->Eflags
;
191 KeTrapFrameToIRQTrapFrame(PKTRAP_FRAME TrapFrame
,
192 PKIRQ_TRAPFRAME IrqTrapFrame
)
194 IrqTrapFrame
->Gs
= TrapFrame
->Gs
;
195 IrqTrapFrame
->Fs
= TrapFrame
->Fs
;
196 IrqTrapFrame
->Es
= TrapFrame
->Es
;
197 IrqTrapFrame
->Ds
= TrapFrame
->Ds
;
198 IrqTrapFrame
->Eax
= TrapFrame
->Eax
;
199 IrqTrapFrame
->Ecx
= TrapFrame
->Ecx
;
200 IrqTrapFrame
->Edx
= TrapFrame
->Edx
;
201 IrqTrapFrame
->Ebx
= TrapFrame
->Ebx
;
202 IrqTrapFrame
->Esp
= TrapFrame
->Esp
;
203 IrqTrapFrame
->Ebp
= TrapFrame
->Ebp
;
204 IrqTrapFrame
->Esi
= TrapFrame
->Esi
;
205 IrqTrapFrame
->Edi
= TrapFrame
->Edi
;
206 IrqTrapFrame
->Eip
= TrapFrame
->Eip
;
207 IrqTrapFrame
->Cs
= TrapFrame
->Cs
;
208 IrqTrapFrame
->Eflags
= TrapFrame
->Eflags
;
212 KiInterruptDispatch2 (ULONG vector
, KIRQL old_level
)
214 * FUNCTION: Calls all the interrupt handlers for a given irq.
216 * vector - The number of the vector to call handlers for.
217 * old_level - The irql of the processor when the irq took place.
218 * NOTES: Must be called at DIRQL.
224 PISR_TABLE CurrentIsr
;
226 DPRINT("I(0x%.08x, 0x%.08x)\n", vector
, old_level
);
229 * Iterate the list until one of the isr tells us its device interrupted
231 CurrentIsr
= &IsrTable
[vector
- IRQ_BASE
][(ULONG
)KeGetCurrentProcessorNumber()];
233 KiAcquireSpinLock(&CurrentIsr
->Lock
);
236 current
= CurrentIsr
->ListHead
.Flink
;
238 while (current
!= &CurrentIsr
->ListHead
)
240 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,InterruptListEntry
);
241 oldlvl
= KeAcquireInterruptSpinLock(isr
);
242 if (isr
->ServiceRoutine(isr
, isr
->ServiceContext
))
244 KeReleaseInterruptSpinLock(isr
, oldlvl
);
247 KeReleaseInterruptSpinLock(isr
, oldlvl
);
248 current
= current
->Flink
;
250 KiReleaseSpinLock(&CurrentIsr
->Lock
);
254 KiInterruptDispatch (ULONG vector
, PKIRQ_TRAPFRAME Trapframe
)
256 * FUNCTION: Calls the irq specific handler for an irq
258 * irq = IRQ that has interrupted
262 KTRAP_FRAME KernelTrapFrame
;
263 PKTHREAD CurrentThread
;
264 PKTRAP_FRAME OldTrapFrame
=NULL
;
267 * At this point we have interrupts disabled, nothing has been done to
271 KeGetCurrentPrcb()->InterruptCount
++;
274 * Notify the rest of the kernel of the raised irq level. For the
275 * default HAL this will send an EOI to the PIC and alter the IRQL.
277 if (!HalBeginSystemInterrupt (vector
,
287 * NOTE: Only higher priority interrupts will get through
289 Ke386EnableInterrupts();
292 if (VECTOR2IRQ(vector
) == 0)
294 KeIRQTrapFrameToTrapFrame(Trapframe
, &KernelTrapFrame
);
295 KeUpdateSystemTime(&KernelTrapFrame
, old_level
);
301 * Actually call the ISR.
303 KiInterruptDispatch2(vector
, old_level
);
307 * End the system interrupt.
309 Ke386DisableInterrupts();
311 if (old_level
==PASSIVE_LEVEL
&& Trapframe
->Cs
!= KGDT_R0_CODE
)
313 HalEndSystemInterrupt (APC_LEVEL
, 0);
315 CurrentThread
= KeGetCurrentThread();
316 if (CurrentThread
!=NULL
&& CurrentThread
->ApcState
.UserApcPending
)
318 DPRINT("PID: %d, TID: %d CS %04x/%04x\n",
319 ((PETHREAD
)CurrentThread
)->ThreadsProcess
->UniqueProcessId
,
320 ((PETHREAD
)CurrentThread
)->Cid
.UniqueThread
,
322 CurrentThread
->TrapFrame
? CurrentThread
->TrapFrame
->Cs
: 0);
323 if (CurrentThread
->TrapFrame
== NULL
)
325 OldTrapFrame
= CurrentThread
->TrapFrame
;
326 KeIRQTrapFrameToTrapFrame(Trapframe
, &KernelTrapFrame
);
327 CurrentThread
->TrapFrame
= &KernelTrapFrame
;
330 Ke386EnableInterrupts();
331 KiDeliverApc(UserMode
, NULL
, NULL
);
332 Ke386DisableInterrupts();
334 ASSERT(KeGetCurrentThread() == CurrentThread
);
335 if (CurrentThread
->TrapFrame
== &KernelTrapFrame
)
337 KeTrapFrameToIRQTrapFrame(&KernelTrapFrame
, Trapframe
);
338 CurrentThread
->TrapFrame
= OldTrapFrame
;
341 KeLowerIrql(PASSIVE_LEVEL
);
345 HalEndSystemInterrupt (old_level
, 0);
354 PLIST_ENTRY current_entry
;
359 for (i
=0;i
<NR_IRQS
;i
++)
362 KeRaiseIrql(VECTOR2IRQL(i
+ IRQ_BASE
),&oldlvl
);
364 for (j
=0; j
< KeNumberProcessors
; j
++)
366 KiAcquireSpinLock(&IsrTable
[i
][j
].Lock
);
368 current_entry
= IsrTable
[i
][j
].ListHead
.Flink
;
369 current
= CONTAINING_RECORD(current_entry
,KINTERRUPT
,InterruptListEntry
);
370 while (current_entry
!=&(IsrTable
[i
][j
].ListHead
))
372 if (printed
== FALSE
)
375 DPRINT("For irq %x:\n",i
);
377 DPRINT(" Isr %x\n",current
);
378 current_entry
= current_entry
->Flink
;
379 current
= CONTAINING_RECORD(current_entry
,KINTERRUPT
,InterruptListEntry
);
381 KiReleaseSpinLock(&IsrTable
[i
][j
].Lock
);
392 KeConnectInterrupt(PKINTERRUPT InterruptObject
)
394 KIRQL oldlvl
,synch_oldlvl
;
395 PKINTERRUPT ListHead
;
397 PISR_TABLE CurrentIsr
;
400 DPRINT("KeConnectInterrupt()\n");
402 Vector
= InterruptObject
->Vector
;
404 if (Vector
< IRQ_BASE
|| Vector
>= IRQ_BASE
+ NR_IRQS
)
409 ASSERT (InterruptObject
->Number
< KeNumberProcessors
);
411 KeSetSystemAffinityThread(1 << InterruptObject
->Number
);
413 CurrentIsr
= &IsrTable
[Vector
][(ULONG
)InterruptObject
->Number
];
415 KeRaiseIrql(VECTOR2IRQL(Vector
+ IRQ_BASE
),&oldlvl
);
416 KiAcquireSpinLock(&CurrentIsr
->Lock
);
419 * Check if the vector is already in use that we can share it
421 if (!IsListEmpty(&CurrentIsr
->ListHead
))
423 ListHead
= CONTAINING_RECORD(CurrentIsr
->ListHead
.Flink
,KINTERRUPT
,InterruptListEntry
);
424 if (InterruptObject
->ShareVector
== FALSE
|| ListHead
->ShareVector
==FALSE
)
426 KiReleaseSpinLock(&CurrentIsr
->Lock
);
428 KeRevertToUserAffinityThread();
433 synch_oldlvl
= KeAcquireInterruptSpinLock(InterruptObject
);
435 DPRINT("%x %x\n",CurrentIsr
->ListHead
.Flink
, CurrentIsr
->ListHead
.Blink
);
437 Result
= HalEnableSystemInterrupt(Vector
+ IRQ_BASE
, InterruptObject
->Irql
, InterruptObject
->Mode
);
440 InsertTailList(&CurrentIsr
->ListHead
,&InterruptObject
->InterruptListEntry
);
441 DPRINT("%x %x\n",InterruptObject
->InterruptListEntry
.Flink
, InterruptObject
->InterruptListEntry
.Blink
);
444 InterruptObject
->Connected
= TRUE
;
445 KeReleaseInterruptSpinLock(InterruptObject
, synch_oldlvl
);
448 * Release the table spinlock
450 KiReleaseSpinLock(&CurrentIsr
->Lock
);
455 KeRevertToUserAffinityThread();
463 * FUNCTION: Releases a drivers isr
465 * InterruptObject = isr to release
469 KeDisconnectInterrupt(PKINTERRUPT InterruptObject
)
471 KIRQL oldlvl
,synch_oldlvl
;
472 PISR_TABLE CurrentIsr
;
475 DPRINT1("KeDisconnectInterrupt\n");
476 ASSERT (InterruptObject
->Number
< KeNumberProcessors
);
478 /* Set the affinity */
479 KeSetSystemAffinityThread(1 << InterruptObject
->Number
);
481 /* Get the ISR Tabe */
482 CurrentIsr
= &IsrTable
[InterruptObject
->Vector
- IRQ_BASE
]
483 [(ULONG
)InterruptObject
->Number
];
485 /* Raise IRQL to required level and lock table */
486 KeRaiseIrql(VECTOR2IRQL(InterruptObject
->Vector
),&oldlvl
);
487 KiAcquireSpinLock(&CurrentIsr
->Lock
);
489 /* Check if it's actually connected */
490 if ((State
= InterruptObject
->Connected
))
492 /* Lock the Interrupt */
493 synch_oldlvl
= KeAcquireInterruptSpinLock(InterruptObject
);
495 /* Remove this one, and check if all are gone */
496 RemoveEntryList(&InterruptObject
->InterruptListEntry
);
497 if (IsListEmpty(&CurrentIsr
->ListHead
))
499 /* Completely Disable the Interrupt */
500 HalDisableSystemInterrupt(InterruptObject
->Vector
, InterruptObject
->Irql
);
504 InterruptObject
->Connected
= FALSE
;
506 /* Release the interrupt lock */
507 KeReleaseInterruptSpinLock(InterruptObject
, synch_oldlvl
);
509 /* Release the table spinlock */
510 KiReleaseSpinLock(&CurrentIsr
->Lock
);
513 /* Go back to default affinity */
514 KeRevertToUserAffinityThread();
516 /* Return Old Interrupt State */
525 KeInitializeInterrupt(PKINTERRUPT Interrupt
,
526 PKSERVICE_ROUTINE ServiceRoutine
,
527 PVOID ServiceContext
,
528 PKSPIN_LOCK SpinLock
,
531 KIRQL SynchronizeIrql
,
532 KINTERRUPT_MODE InterruptMode
,
534 CHAR ProcessorNumber
,
535 BOOLEAN FloatingSave
)
537 /* Set the Interrupt Header */
538 Interrupt
->Type
= InterruptObject
;
539 Interrupt
->Size
= sizeof(KINTERRUPT
);
541 /* Check if we got a spinlock */
544 Interrupt
->ActualLock
= SpinLock
;
548 /* This means we'll be usin the built-in one */
549 KeInitializeSpinLock(&Interrupt
->SpinLock
);
550 Interrupt
->ActualLock
= &Interrupt
->SpinLock
;
553 /* Set the other settings */
554 Interrupt
->ServiceRoutine
= ServiceRoutine
;
555 Interrupt
->ServiceContext
= ServiceContext
;
556 Interrupt
->Vector
= Vector
;
557 Interrupt
->Irql
= Irql
;
558 Interrupt
->SynchronizeIrql
= SynchronizeIrql
;
559 Interrupt
->Mode
= InterruptMode
;
560 Interrupt
->ShareVector
= ShareVector
;
561 Interrupt
->Number
= ProcessorNumber
;
562 Interrupt
->FloatingSave
= FloatingSave
;
564 /* Disconnect it at first */
565 Interrupt
->Connected
= FALSE
;
568 VOID
KePrintInterruptStatistic(VOID
)
572 for (j
= 0; j
< KeNumberProcessors
; j
++)
574 DPRINT1("CPU%d:\n", j
);
575 for (i
= 0; i
< NR_IRQS
; i
++)
577 if (IsrTable
[i
][j
].Count
)
579 DPRINT1(" Irq %x(%d): %d\n", i
, VECTOR2IRQ(i
+ IRQ_BASE
), IsrTable
[i
][j
].Count
);