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)
141 KeInitInterrupts (VOID
)
147 * Setup the IDT entries to point to the interrupt handlers
149 for (i
=0;i
<NR_IRQS
;i
++)
151 KiIdt
[IRQ_BASE
+i
].a
=(irq_handler
[i
]&0xffff)+(KERNEL_CS
<<16);
152 KiIdt
[IRQ_BASE
+i
].b
=(irq_handler
[i
]&0xffff0000)+PRESENT
+
155 for (j
= 0; j
< MAXIMUM_PROCESSORS
; j
++)
160 InitializeListHead(&IsrTable
[i
][j
].ListHead
);
161 KeInitializeSpinLock(&IsrTable
[i
][j
].Lock
);
162 IsrTable
[i
][j
].Count
= 0;
168 KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame
,
169 PKTRAP_FRAME TrapFrame
)
171 TrapFrame
->Gs
= (USHORT
)IrqTrapFrame
->Gs
;
172 TrapFrame
->Fs
= (USHORT
)IrqTrapFrame
->Fs
;
173 TrapFrame
->Es
= (USHORT
)IrqTrapFrame
->Es
;
174 TrapFrame
->Ds
= (USHORT
)IrqTrapFrame
->Ds
;
175 TrapFrame
->Eax
= IrqTrapFrame
->Eax
;
176 TrapFrame
->Ecx
= IrqTrapFrame
->Ecx
;
177 TrapFrame
->Edx
= IrqTrapFrame
->Edx
;
178 TrapFrame
->Ebx
= IrqTrapFrame
->Ebx
;
179 TrapFrame
->Esp
= IrqTrapFrame
->Esp
;
180 TrapFrame
->Ebp
= IrqTrapFrame
->Ebp
;
181 TrapFrame
->Esi
= IrqTrapFrame
->Esi
;
182 TrapFrame
->Edi
= IrqTrapFrame
->Edi
;
183 TrapFrame
->Eip
= IrqTrapFrame
->Eip
;
184 TrapFrame
->Cs
= IrqTrapFrame
->Cs
;
185 TrapFrame
->Eflags
= IrqTrapFrame
->Eflags
;
189 KeTrapFrameToIRQTrapFrame(PKTRAP_FRAME TrapFrame
,
190 PKIRQ_TRAPFRAME IrqTrapFrame
)
192 IrqTrapFrame
->Gs
= TrapFrame
->Gs
;
193 IrqTrapFrame
->Fs
= TrapFrame
->Fs
;
194 IrqTrapFrame
->Es
= TrapFrame
->Es
;
195 IrqTrapFrame
->Ds
= TrapFrame
->Ds
;
196 IrqTrapFrame
->Eax
= TrapFrame
->Eax
;
197 IrqTrapFrame
->Ecx
= TrapFrame
->Ecx
;
198 IrqTrapFrame
->Edx
= TrapFrame
->Edx
;
199 IrqTrapFrame
->Ebx
= TrapFrame
->Ebx
;
200 IrqTrapFrame
->Esp
= TrapFrame
->Esp
;
201 IrqTrapFrame
->Ebp
= TrapFrame
->Ebp
;
202 IrqTrapFrame
->Esi
= TrapFrame
->Esi
;
203 IrqTrapFrame
->Edi
= TrapFrame
->Edi
;
204 IrqTrapFrame
->Eip
= TrapFrame
->Eip
;
205 IrqTrapFrame
->Cs
= TrapFrame
->Cs
;
206 IrqTrapFrame
->Eflags
= TrapFrame
->Eflags
;
210 KiInterruptDispatch2 (ULONG vector
, KIRQL old_level
)
212 * FUNCTION: Calls all the interrupt handlers for a given irq.
214 * vector - The number of the vector to call handlers for.
215 * old_level - The irql of the processor when the irq took place.
216 * NOTES: Must be called at DIRQL.
222 PISR_TABLE CurrentIsr
;
224 DPRINT("I(0x%.08x, 0x%.08x)\n", vector
, old_level
);
227 * Iterate the list until one of the isr tells us its device interrupted
229 CurrentIsr
= &IsrTable
[vector
- IRQ_BASE
][(ULONG
)KeGetCurrentProcessorNumber()];
231 KiAcquireSpinLock(&CurrentIsr
->Lock
);
234 current
= CurrentIsr
->ListHead
.Flink
;
236 while (current
!= &CurrentIsr
->ListHead
)
238 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,InterruptListEntry
);
239 oldlvl
= KeAcquireInterruptSpinLock(isr
);
240 if (isr
->ServiceRoutine(isr
, isr
->ServiceContext
))
242 KeReleaseInterruptSpinLock(isr
, oldlvl
);
245 KeReleaseInterruptSpinLock(isr
, oldlvl
);
246 current
= current
->Flink
;
248 KiReleaseSpinLock(&CurrentIsr
->Lock
);
252 KiInterruptDispatch (ULONG vector
, PKIRQ_TRAPFRAME Trapframe
)
254 * FUNCTION: Calls the irq specific handler for an irq
256 * irq = IRQ that has interrupted
260 KTRAP_FRAME KernelTrapFrame
;
261 PKTHREAD CurrentThread
;
262 PKTRAP_FRAME OldTrapFrame
=NULL
;
265 * At this point we have interrupts disabled, nothing has been done to
269 KeGetCurrentPrcb()->InterruptCount
++;
272 * Notify the rest of the kernel of the raised irq level. For the
273 * default HAL this will send an EOI to the PIC and alter the IRQL.
275 if (!HalBeginSystemInterrupt (vector
,
285 * NOTE: Only higher priority interrupts will get through
287 Ke386EnableInterrupts();
290 if (VECTOR2IRQ(vector
) == 0)
292 KeIRQTrapFrameToTrapFrame(Trapframe
, &KernelTrapFrame
);
293 KeUpdateSystemTime(&KernelTrapFrame
, old_level
);
299 * Actually call the ISR.
301 KiInterruptDispatch2(vector
, old_level
);
305 * End the system interrupt.
307 Ke386DisableInterrupts();
309 HalEndSystemInterrupt (old_level
, 0);
311 if (old_level
==PASSIVE_LEVEL
&& Trapframe
->Cs
!= KERNEL_CS
)
313 CurrentThread
= KeGetCurrentThread();
314 if (CurrentThread
!=NULL
&& CurrentThread
->Alerted
[1])
316 DPRINT("PID: %d, TID: %d CS %04x/%04x\n",
317 ((PETHREAD
)CurrentThread
)->ThreadsProcess
->UniqueProcessId
,
318 ((PETHREAD
)CurrentThread
)->Cid
.UniqueThread
,
320 CurrentThread
->TrapFrame
? CurrentThread
->TrapFrame
->Cs
: 0);
321 if (CurrentThread
->TrapFrame
== NULL
)
323 OldTrapFrame
= CurrentThread
->TrapFrame
;
324 KeIRQTrapFrameToTrapFrame(Trapframe
, &KernelTrapFrame
);
325 CurrentThread
->TrapFrame
= &KernelTrapFrame
;
328 Ke386EnableInterrupts();
329 KiDeliverApc(KernelMode
, NULL
, NULL
);
330 Ke386DisableInterrupts();
332 ASSERT(KeGetCurrentThread() == CurrentThread
);
333 if (CurrentThread
->TrapFrame
== &KernelTrapFrame
)
335 KeTrapFrameToIRQTrapFrame(&KernelTrapFrame
, Trapframe
);
336 CurrentThread
->TrapFrame
= OldTrapFrame
;
346 PLIST_ENTRY current_entry
;
351 for (i
=0;i
<NR_IRQS
;i
++)
354 KeRaiseIrql(VECTOR2IRQL(i
+ IRQ_BASE
),&oldlvl
);
356 for (j
=0; j
< KeNumberProcessors
; j
++)
358 KiAcquireSpinLock(&IsrTable
[i
][j
].Lock
);
360 current_entry
= IsrTable
[i
][j
].ListHead
.Flink
;
361 current
= CONTAINING_RECORD(current_entry
,KINTERRUPT
,InterruptListEntry
);
362 while (current_entry
!=&(IsrTable
[i
][j
].ListHead
))
364 if (printed
== FALSE
)
367 DPRINT("For irq %x:\n",i
);
369 DPRINT(" Isr %x\n",current
);
370 current_entry
= current_entry
->Flink
;
371 current
= CONTAINING_RECORD(current_entry
,KINTERRUPT
,InterruptListEntry
);
373 KiReleaseSpinLock(&IsrTable
[i
][j
].Lock
);
384 KeConnectInterrupt(PKINTERRUPT InterruptObject
)
386 KIRQL oldlvl
,synch_oldlvl
;
387 PKINTERRUPT ListHead
;
389 PISR_TABLE CurrentIsr
;
392 DPRINT("KeConnectInterrupt()\n");
394 Vector
= InterruptObject
->Vector
;
396 if (Vector
< IRQ_BASE
|| Vector
>= IRQ_BASE
+ NR_IRQS
)
401 ASSERT (InterruptObject
->Number
< KeNumberProcessors
);
403 KeSetSystemAffinityThread(1 << InterruptObject
->Number
);
405 CurrentIsr
= &IsrTable
[Vector
][(ULONG
)InterruptObject
->Number
];
407 KeRaiseIrql(VECTOR2IRQL(Vector
+ IRQ_BASE
),&oldlvl
);
408 KiAcquireSpinLock(&CurrentIsr
->Lock
);
411 * Check if the vector is already in use that we can share it
413 if (!IsListEmpty(&CurrentIsr
->ListHead
))
415 ListHead
= CONTAINING_RECORD(CurrentIsr
->ListHead
.Flink
,KINTERRUPT
,InterruptListEntry
);
416 if (InterruptObject
->ShareVector
== FALSE
|| ListHead
->ShareVector
==FALSE
)
418 KiReleaseSpinLock(&CurrentIsr
->Lock
);
420 KeRevertToUserAffinityThread();
425 synch_oldlvl
= KeAcquireInterruptSpinLock(InterruptObject
);
427 DPRINT("%x %x\n",CurrentIsr
->ListHead
.Flink
, CurrentIsr
->ListHead
.Blink
);
429 Result
= HalEnableSystemInterrupt(Vector
+ IRQ_BASE
, InterruptObject
->Irql
, InterruptObject
->Mode
);
432 InsertTailList(&CurrentIsr
->ListHead
,&InterruptObject
->InterruptListEntry
);
433 DPRINT("%x %x\n",InterruptObject
->InterruptListEntry
.Flink
, InterruptObject
->InterruptListEntry
.Blink
);
436 InterruptObject
->Connected
= TRUE
;
437 KeReleaseInterruptSpinLock(InterruptObject
, synch_oldlvl
);
440 * Release the table spinlock
442 KiReleaseSpinLock(&CurrentIsr
->Lock
);
447 KeRevertToUserAffinityThread();
455 * FUNCTION: Releases a drivers isr
457 * InterruptObject = isr to release
461 KeDisconnectInterrupt(PKINTERRUPT InterruptObject
)
463 KIRQL oldlvl
,synch_oldlvl
;
464 PISR_TABLE CurrentIsr
;
467 DPRINT1("KeDisconnectInterrupt\n");
468 ASSERT (InterruptObject
->Number
< KeNumberProcessors
);
470 /* Set the affinity */
471 KeSetSystemAffinityThread(1 << InterruptObject
->Number
);
473 /* Get the ISR Tabe */
474 CurrentIsr
= &IsrTable
[InterruptObject
->Vector
- IRQ_BASE
]
475 [(ULONG
)InterruptObject
->Number
];
477 /* Raise IRQL to required level and lock table */
478 KeRaiseIrql(VECTOR2IRQL(InterruptObject
->Vector
),&oldlvl
);
479 KiAcquireSpinLock(&CurrentIsr
->Lock
);
481 /* Check if it's actually connected */
482 if ((State
= InterruptObject
->Connected
))
484 /* Lock the Interrupt */
485 synch_oldlvl
= KeAcquireInterruptSpinLock(InterruptObject
);
487 /* Remove this one, and check if all are gone */
488 RemoveEntryList(&InterruptObject
->InterruptListEntry
);
489 if (IsListEmpty(&CurrentIsr
->ListHead
))
491 /* Completely Disable the Interrupt */
492 HalDisableSystemInterrupt(InterruptObject
->Vector
, InterruptObject
->Irql
);
496 InterruptObject
->Connected
= FALSE
;
498 /* Release the interrupt lock */
499 KeReleaseInterruptSpinLock(InterruptObject
, synch_oldlvl
);
501 /* Release the table spinlock */
502 KiReleaseSpinLock(&CurrentIsr
->Lock
);
505 /* Go back to default affinity */
506 KeRevertToUserAffinityThread();
508 /* Return Old Interrupt State */
517 KeInitializeInterrupt(PKINTERRUPT Interrupt
,
518 PKSERVICE_ROUTINE ServiceRoutine
,
519 PVOID ServiceContext
,
520 PKSPIN_LOCK SpinLock
,
523 KIRQL SynchronizeIrql
,
524 KINTERRUPT_MODE InterruptMode
,
526 CHAR ProcessorNumber
,
527 BOOLEAN FloatingSave
)
529 /* Set the Interrupt Header */
530 Interrupt
->Type
= InterruptObject
;
531 Interrupt
->Size
= sizeof(KINTERRUPT
);
533 /* Check if we got a spinlock */
536 Interrupt
->ActualLock
= SpinLock
;
540 /* This means we'll be usin the built-in one */
541 KeInitializeSpinLock(&Interrupt
->SpinLock
);
542 Interrupt
->ActualLock
= &Interrupt
->SpinLock
;
545 /* Set the other settings */
546 Interrupt
->ServiceRoutine
= ServiceRoutine
;
547 Interrupt
->ServiceContext
= ServiceContext
;
548 Interrupt
->Vector
= Vector
;
549 Interrupt
->Irql
= Irql
;
550 Interrupt
->SynchronizeIrql
= SynchronizeIrql
;
551 Interrupt
->Mode
= InterruptMode
;
552 Interrupt
->ShareVector
= ShareVector
;
553 Interrupt
->Number
= ProcessorNumber
;
554 Interrupt
->FloatingSave
= FloatingSave
;
556 /* Disconnect it at first */
557 Interrupt
->Connected
= FALSE
;
560 VOID
KePrintInterruptStatistic(VOID
)
564 for (j
= 0; j
< KeNumberProcessors
; j
++)
566 DPRINT1("CPU%d:\n", j
);
567 for (i
= 0; i
< NR_IRQS
; i
++)
569 if (IsrTable
[i
][j
].Count
)
571 DPRINT1(" Irq %x(%d): %d\n", i
, VECTOR2IRQ(i
+ IRQ_BASE
), IsrTable
[i
][j
].Count
);