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 #if defined(KDBG) || defined(DBG)
23 #include <../dbg/kdb.h>
26 #include <../hal/halx86/include/halirq.h>
29 #include <internal/debug.h>
31 /* GLOBALS *****************************************************************/
36 #define STR(x) __STR(x)
38 #define INT_NAME(intnum) _KiUnexpectedInterrupt##intnum
39 #define INT_NAME2(intnum) KiUnexpectedInterrupt##intnum
41 #define BUILD_COMMON_INTERRUPT_HANDLER() \
43 "_KiCommonInterrupt:\n\t" \
49 "movl $0xceafbeef,%eax\n\t" \
51 "movl $" STR(KERNEL_DS) ",%eax\n\t" \
55 "movl $" STR(PCR_SELECTOR) ",%eax\n\t" \
59 "call _KiInterruptDispatch\n\t" \
70 #define BUILD_INTERRUPT_HANDLER(intnum) \
71 VOID INT_NAME2(intnum)(VOID); \
73 STR(INT_NAME(intnum)) ":\n\t" \
75 "movl $0x" STR(intnum) ",%ebx\n\t" \
76 "jmp _KiCommonInterrupt");
79 /* Interrupt handlers and declarations */
82 BUILD_INTERRUPT_HANDLER(x##y)
85 B(x,0) B(x,1) B(x,2) B(x,3) \
86 B(x,4) B(x,5) B(x,6) B(x,7) \
87 B(x,8) B(x,9) B(x,A) B(x,B) \
88 B(x,C) B(x,D) B(x,E) B(x,F)
91 BUILD_COMMON_INTERRUPT_HANDLER()
92 B16(3) B16(4) B16(5) B16(6)
93 B16(7) B16(8) B16(9) B16(A
)
94 B16(B
) B16(C
) B16(D
) B16(E
)
101 /* Interrupt handler list */
104 (ULONG)& INT_NAME2(x##y)
107 L(x,0), L(x,1), L(x,2), L(x,3), \
108 L(x,4), L(x,5), L(x,6), L(x,7), \
109 L(x,8), L(x,9), L(x,A), L(x,B), \
110 L(x,C), L(x,D), L(x,E), L(x,F)
112 static ULONG irq_handler
[ROUND_UP(NR_IRQS
, 16)] = {
113 L16(3), L16(4), L16(5), L16(6),
114 L16(7), L16(8), L16(9), L16(A
),
115 L16(B
), L16(C
), L16(D
), L16(E
)
121 #else /* CONFIG_SMP */
123 void irq_handler_0(void);
124 void irq_handler_1(void);
125 void irq_handler_2(void);
126 void irq_handler_3(void);
127 void irq_handler_4(void);
128 void irq_handler_5(void);
129 void irq_handler_6(void);
130 void irq_handler_7(void);
131 void irq_handler_8(void);
132 void irq_handler_9(void);
133 void irq_handler_10(void);
134 void irq_handler_11(void);
135 void irq_handler_12(void);
136 void irq_handler_13(void);
137 void irq_handler_14(void);
138 void irq_handler_15(void);
140 static unsigned int irq_handler
[NR_IRQS
]=
152 (int)&irq_handler_10
,
153 (int)&irq_handler_11
,
154 (int)&irq_handler_12
,
155 (int)&irq_handler_13
,
156 (int)&irq_handler_14
,
157 (int)&irq_handler_15
,
160 #endif /* CONFIG_SMP */
163 * PURPOSE: Object describing each isr
164 * NOTE: The data in this table is only modified at passsive level but can
165 * be accessed at any irq level.
174 ISR_TABLE
, *PISR_TABLE
;
177 static ISR_TABLE IsrTable
[NR_IRQS
][MAXIMUM_PROCESSORS
];
179 static ISR_TABLE IsrTable
[NR_IRQS
][1];
182 #define TAG_ISR_LOCK TAG('I', 'S', 'R', 'L')
184 /* FUNCTIONS ****************************************************************/
186 #define PRESENT (0x8000)
187 #define I486_INTERRUPT_GATE (0xe00)
190 KeInitInterrupts (VOID
)
196 * Setup the IDT entries to point to the interrupt handlers
198 for (i
=0;i
<NR_IRQS
;i
++)
200 KiIdt
[IRQ_BASE
+i
].a
=(irq_handler
[i
]&0xffff)+(KERNEL_CS
<<16);
201 KiIdt
[IRQ_BASE
+i
].b
=(irq_handler
[i
]&0xffff0000)+PRESENT
+
204 for (j
= 0; j
< MAXIMUM_PROCESSORS
; j
++)
209 InitializeListHead(&IsrTable
[i
][j
].ListHead
);
210 KeInitializeSpinLock(&IsrTable
[i
][j
].Lock
);
211 IsrTable
[i
][j
].Count
= 0;
217 KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame
,
218 PKTRAP_FRAME TrapFrame
)
220 TrapFrame
->Gs
= (USHORT
)IrqTrapFrame
->Gs
;
221 TrapFrame
->Fs
= (USHORT
)IrqTrapFrame
->Fs
;
222 TrapFrame
->Es
= (USHORT
)IrqTrapFrame
->Es
;
223 TrapFrame
->Ds
= (USHORT
)IrqTrapFrame
->Ds
;
224 TrapFrame
->Eax
= IrqTrapFrame
->Eax
;
225 TrapFrame
->Ecx
= IrqTrapFrame
->Ecx
;
226 TrapFrame
->Edx
= IrqTrapFrame
->Edx
;
227 TrapFrame
->Ebx
= IrqTrapFrame
->Ebx
;
228 TrapFrame
->Esp
= IrqTrapFrame
->Esp
;
229 TrapFrame
->Ebp
= IrqTrapFrame
->Ebp
;
230 TrapFrame
->Esi
= IrqTrapFrame
->Esi
;
231 TrapFrame
->Edi
= IrqTrapFrame
->Edi
;
232 TrapFrame
->Eip
= IrqTrapFrame
->Eip
;
233 TrapFrame
->Cs
= IrqTrapFrame
->Cs
;
234 TrapFrame
->Eflags
= IrqTrapFrame
->Eflags
;
238 KeTrapFrameToIRQTrapFrame(PKTRAP_FRAME TrapFrame
,
239 PKIRQ_TRAPFRAME IrqTrapFrame
)
241 IrqTrapFrame
->Gs
= TrapFrame
->Gs
;
242 IrqTrapFrame
->Fs
= TrapFrame
->Fs
;
243 IrqTrapFrame
->Es
= TrapFrame
->Es
;
244 IrqTrapFrame
->Ds
= TrapFrame
->Ds
;
245 IrqTrapFrame
->Eax
= TrapFrame
->Eax
;
246 IrqTrapFrame
->Ecx
= TrapFrame
->Ecx
;
247 IrqTrapFrame
->Edx
= TrapFrame
->Edx
;
248 IrqTrapFrame
->Ebx
= TrapFrame
->Ebx
;
249 IrqTrapFrame
->Esp
= TrapFrame
->Esp
;
250 IrqTrapFrame
->Ebp
= TrapFrame
->Ebp
;
251 IrqTrapFrame
->Esi
= TrapFrame
->Esi
;
252 IrqTrapFrame
->Edi
= TrapFrame
->Edi
;
253 IrqTrapFrame
->Eip
= TrapFrame
->Eip
;
254 IrqTrapFrame
->Cs
= TrapFrame
->Cs
;
255 IrqTrapFrame
->Eflags
= TrapFrame
->Eflags
;
259 KiInterruptDispatch2 (ULONG vector
, KIRQL old_level
)
261 * FUNCTION: Calls all the interrupt handlers for a given irq.
263 * vector - The number of the vector to call handlers for.
264 * old_level - The irql of the processor when the irq took place.
265 * NOTES: Must be called at DIRQL.
271 PISR_TABLE CurrentIsr
;
273 DPRINT("I(0x%.08x, 0x%.08x)\n", vector
, old_level
);
276 * Iterate the list until one of the isr tells us its device interrupted
278 CurrentIsr
= &IsrTable
[vector
- IRQ_BASE
][(ULONG
)KeGetCurrentProcessorNumber()];
280 KiAcquireSpinLock(&CurrentIsr
->Lock
);
283 current
= CurrentIsr
->ListHead
.Flink
;
285 while (current
!= &CurrentIsr
->ListHead
)
287 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
288 oldlvl
= KeAcquireInterruptSpinLock(isr
);
289 if (isr
->ServiceRoutine(isr
, isr
->ServiceContext
))
291 KeReleaseInterruptSpinLock(isr
, oldlvl
);
294 KeReleaseInterruptSpinLock(isr
, oldlvl
);
295 current
= current
->Flink
;
297 KiReleaseSpinLock(&CurrentIsr
->Lock
);
301 KiInterruptDispatch (ULONG vector
, PKIRQ_TRAPFRAME Trapframe
)
303 * FUNCTION: Calls the irq specific handler for an irq
305 * irq = IRQ that has interrupted
309 KTRAP_FRAME KernelTrapFrame
;
310 PKTHREAD CurrentThread
;
311 PKTRAP_FRAME OldTrapFrame
=NULL
;
314 * At this point we have interrupts disabled, nothing has been done to
318 KeGetCurrentKPCR()->PrcbData
.InterruptCount
++;
321 * Notify the rest of the kernel of the raised irq level. For the
322 * default HAL this will send an EOI to the PIC and alter the IRQL.
324 if (!HalBeginSystemInterrupt (vector
,
334 * NOTE: Only higher priority interrupts will get through
336 Ke386EnableInterrupts();
339 if (VECTOR2IRQ(vector
) == 0)
341 KeIRQTrapFrameToTrapFrame(Trapframe
, &KernelTrapFrame
);
342 KeUpdateSystemTime(&KernelTrapFrame
, old_level
);
343 #if defined(KDBG) || defined(DBG)
344 KdbProfileInterrupt(Trapframe
->Eip
);
351 * Actually call the ISR.
353 KiInterruptDispatch2(vector
, old_level
);
357 * End the system interrupt.
359 Ke386DisableInterrupts();
361 HalEndSystemInterrupt (old_level
, 0);
363 if (old_level
==PASSIVE_LEVEL
&& Trapframe
->Cs
!= KERNEL_CS
)
365 CurrentThread
= KeGetCurrentThread();
366 if (CurrentThread
!=NULL
&& CurrentThread
->Alerted
[1])
368 DPRINT("PID: %d, TID: %d CS %04x/%04x\n",
369 ((PETHREAD
)CurrentThread
)->ThreadsProcess
->UniqueProcessId
,
370 ((PETHREAD
)CurrentThread
)->Cid
.UniqueThread
,
372 CurrentThread
->TrapFrame
? CurrentThread
->TrapFrame
->Cs
: 0);
373 if (CurrentThread
->TrapFrame
== NULL
)
375 OldTrapFrame
= CurrentThread
->TrapFrame
;
376 KeIRQTrapFrameToTrapFrame(Trapframe
, &KernelTrapFrame
);
377 CurrentThread
->TrapFrame
= &KernelTrapFrame
;
380 Ke386EnableInterrupts();
381 KiDeliverApc(KernelMode
, NULL
, NULL
);
382 Ke386DisableInterrupts();
384 ASSERT(KeGetCurrentThread() == CurrentThread
);
385 if (CurrentThread
->TrapFrame
== &KernelTrapFrame
)
387 KeTrapFrameToIRQTrapFrame(&KernelTrapFrame
, Trapframe
);
388 CurrentThread
->TrapFrame
= OldTrapFrame
;
398 PLIST_ENTRY current_entry
;
403 for (i
=0;i
<NR_IRQS
;i
++)
406 KeRaiseIrql(VECTOR2IRQL(i
+ IRQ_BASE
),&oldlvl
);
408 for (j
=0; j
< KeNumberProcessors
; j
++)
410 KiAcquireSpinLock(&IsrTable
[i
][j
].Lock
);
412 current_entry
= IsrTable
[i
][j
].ListHead
.Flink
;
413 current
= CONTAINING_RECORD(current_entry
,KINTERRUPT
,Entry
);
414 while (current_entry
!=&(IsrTable
[i
][j
].ListHead
))
416 if (printed
== FALSE
)
419 DPRINT("For irq %x:\n",i
);
421 DPRINT(" Isr %x\n",current
);
422 current_entry
= current_entry
->Flink
;
423 current
= CONTAINING_RECORD(current_entry
,KINTERRUPT
,Entry
);
425 KiReleaseSpinLock(&IsrTable
[i
][j
].Lock
);
435 KeConnectInterrupt(PKINTERRUPT InterruptObject
)
437 KIRQL oldlvl
,synch_oldlvl
;
438 PKINTERRUPT ListHead
;
440 PISR_TABLE CurrentIsr
;
443 DPRINT("KeConnectInterrupt()\n");
445 Vector
= InterruptObject
->Vector
;
447 if (Vector
< IRQ_BASE
|| Vector
>= IRQ_BASE
+ NR_IRQS
)
452 ASSERT (InterruptObject
->ProcessorNumber
< KeNumberProcessors
);
454 KeSetSystemAffinityThread(1 << InterruptObject
->ProcessorNumber
);
456 CurrentIsr
= &IsrTable
[Vector
][(ULONG
)InterruptObject
->ProcessorNumber
];
458 KeRaiseIrql(VECTOR2IRQL(Vector
+ IRQ_BASE
),&oldlvl
);
459 KiAcquireSpinLock(&CurrentIsr
->Lock
);
462 * Check if the vector is already in use that we can share it
464 if (!IsListEmpty(&CurrentIsr
->ListHead
))
466 ListHead
= CONTAINING_RECORD(CurrentIsr
->ListHead
.Flink
,KINTERRUPT
,Entry
);
467 if (InterruptObject
->Shareable
== FALSE
|| ListHead
->Shareable
==FALSE
)
469 KiReleaseSpinLock(&CurrentIsr
->Lock
);
471 KeRevertToUserAffinityThread();
476 synch_oldlvl
= KeAcquireInterruptSpinLock(InterruptObject
);
478 DPRINT("%x %x\n",CurrentIsr
->ListHead
.Flink
, CurrentIsr
->ListHead
.Blink
);
480 Result
= HalEnableSystemInterrupt(Vector
+ IRQ_BASE
, InterruptObject
->Irql
, InterruptObject
->InterruptMode
);
483 InsertTailList(&CurrentIsr
->ListHead
,&InterruptObject
->Entry
);
484 DPRINT("%x %x\n",InterruptObject
->Entry
.Flink
, InterruptObject
->Entry
.Blink
);
487 KeReleaseInterruptSpinLock(InterruptObject
, synch_oldlvl
);
490 * Release the table spinlock
492 KiReleaseSpinLock(&CurrentIsr
->Lock
);
497 KeRevertToUserAffinityThread();
507 KeDisconnectInterrupt(PKINTERRUPT InterruptObject
)
509 * FUNCTION: Releases a drivers isr
511 * InterruptObject = isr to release
514 KIRQL oldlvl
,synch_oldlvl
;
515 PISR_TABLE CurrentIsr
;
517 DPRINT("KeDisconnectInterrupt\n");
519 ASSERT (InterruptObject
->ProcessorNumber
< KeNumberProcessors
);
521 KeSetSystemAffinityThread(1 << InterruptObject
->ProcessorNumber
);
523 CurrentIsr
= &IsrTable
[InterruptObject
->Vector
- IRQ_BASE
][(ULONG
)InterruptObject
->ProcessorNumber
];
525 KeRaiseIrql(VECTOR2IRQL(InterruptObject
->Vector
),&oldlvl
);
526 KiAcquireSpinLock(&CurrentIsr
->Lock
);
528 synch_oldlvl
= KeAcquireInterruptSpinLock(InterruptObject
);
530 RemoveEntryList(&InterruptObject
->Entry
);
531 if (IsListEmpty(&CurrentIsr
->ListHead
))
533 HalDisableSystemInterrupt(InterruptObject
->Vector
, 0);
535 KeReleaseInterruptSpinLock(InterruptObject
, synch_oldlvl
);
538 * Release the table spinlock
540 KiReleaseSpinLock(&CurrentIsr
->Lock
);
543 KeRevertToUserAffinityThread();
552 KeInitializeInterrupt(PKINTERRUPT InterruptObject
,
553 PKSERVICE_ROUTINE ServiceRoutine
,
554 PVOID ServiceContext
,
555 PKSPIN_LOCK SpinLock
,
558 KIRQL SynchronizeIrql
,
559 KINTERRUPT_MODE InterruptMode
,
561 CHAR ProcessorNumber
,
562 BOOLEAN FloatingSave
)
564 InterruptObject
->ServiceRoutine
= ServiceRoutine
;
565 InterruptObject
->ServiceContext
= ServiceContext
;
566 InterruptObject
->ActualLock
= SpinLock
;
567 InterruptObject
->Vector
= Vector
;
568 InterruptObject
->Irql
= Irql
;
569 InterruptObject
->SynchLevel
= SynchronizeIrql
;
570 InterruptObject
->InterruptMode
= InterruptMode
;
571 InterruptObject
->Shareable
= ShareVector
;
572 InterruptObject
->ProcessorNumber
= ProcessorNumber
;
573 InterruptObject
->FloatingSave
= FloatingSave
;
576 VOID
KePrintInterruptStatistic(VOID
)
580 for (j
= 0; j
< KeNumberProcessors
; j
++)
582 DPRINT1("CPU%d:\n", j
);
583 for (i
= 0; i
< NR_IRQS
; i
++)
585 if (IsrTable
[i
][j
].Count
)
587 DPRINT1(" Irq %x(%d): %d\n", i
, VECTOR2IRQ(i
+ IRQ_BASE
), IsrTable
[i
][j
].Count
);