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 *****************************************************************/
32 #define STR(x) __STR(x)
34 #define INT_NAME(intnum) _KiUnexpectedInterrupt##intnum
35 #define INT_NAME2(intnum) KiUnexpectedInterrupt##intnum
37 #define BUILD_COMMON_INTERRUPT_HANDLER() \
39 "_KiCommonInterrupt:\n\t" \
45 "movl $0xceafbeef,%eax\n\t" \
47 "movl $" STR(KERNEL_DS) ",%eax\n\t" \
51 "movl $" STR(PCR_SELECTOR) ",%eax\n\t" \
55 "call _KiInterruptDispatch\n\t" \
56 "addl $0xC, %esp\n\t" \
64 #define BUILD_INTERRUPT_HANDLER(intnum) \
65 VOID INT_NAME2(intnum)(VOID); \
67 STR(INT_NAME(intnum)) ":\n\t" \
69 "movl $0x" STR(intnum) ",%ebx\n\t" \
70 "jmp _KiCommonInterrupt");
73 /* Interrupt handlers and declarations */
76 BUILD_INTERRUPT_HANDLER(x##y)
79 B(x,0) B(x,1) B(x,2) B(x,3) \
80 B(x,4) B(x,5) B(x,6) B(x,7) \
81 B(x,8) B(x,9) B(x,A) B(x,B) \
82 B(x,C) B(x,D) B(x,E) B(x,F)
85 BUILD_COMMON_INTERRUPT_HANDLER()
86 B16(3) B16(4) B16(5) B16(6)
87 B16(7) B16(8) B16(9) B16(A
)
88 B16(B
) B16(C
) B16(D
) B16(E
)
95 /* Interrupt handler list */
98 (ULONG)& INT_NAME2(x##y)
101 L(x,0), L(x,1), L(x,2), L(x,3), \
102 L(x,4), L(x,5), L(x,6), L(x,7), \
103 L(x,8), L(x,9), L(x,A), L(x,B), \
104 L(x,C), L(x,D), L(x,E), L(x,F)
106 static ULONG irq_handler
[ROUND_UP(NR_IRQS
, 16)] = {
107 L16(3), L16(4), L16(5), L16(6),
108 L16(7), L16(8), L16(9), L16(A
),
109 L16(B
), L16(C
), L16(D
), L16(E
)
115 #else /* CONFIG_SMP */
117 void irq_handler_0(void);
118 void irq_handler_1(void);
119 void irq_handler_2(void);
120 void irq_handler_3(void);
121 void irq_handler_4(void);
122 void irq_handler_5(void);
123 void irq_handler_6(void);
124 void irq_handler_7(void);
125 void irq_handler_8(void);
126 void irq_handler_9(void);
127 void irq_handler_10(void);
128 void irq_handler_11(void);
129 void irq_handler_12(void);
130 void irq_handler_13(void);
131 void irq_handler_14(void);
132 void irq_handler_15(void);
134 static unsigned int irq_handler
[NR_IRQS
]=
146 (int)&irq_handler_10
,
147 (int)&irq_handler_11
,
148 (int)&irq_handler_12
,
149 (int)&irq_handler_13
,
150 (int)&irq_handler_14
,
151 (int)&irq_handler_15
,
154 #endif /* CONFIG_SMP */
157 * PURPOSE: Object describing each isr
158 * NOTE: The data in this table is only modified at passsive level but can
159 * be accessed at any irq level.
168 ISR_TABLE
, *PISR_TABLE
;
171 static ISR_TABLE IsrTable
[NR_IRQS
][MAXIMUM_PROCESSORS
];
173 static ISR_TABLE IsrTable
[NR_IRQS
][1];
176 #define TAG_ISR_LOCK TAG('I', 'S', 'R', 'L')
178 /* FUNCTIONS ****************************************************************/
180 #define PRESENT (0x8000)
181 #define I486_INTERRUPT_GATE (0xe00)
184 KeInitInterrupts (VOID
)
190 * Setup the IDT entries to point to the interrupt handlers
192 for (i
=0;i
<NR_IRQS
;i
++)
194 KiIdt
[IRQ_BASE
+i
].a
=(irq_handler
[i
]&0xffff)+(KERNEL_CS
<<16);
195 KiIdt
[IRQ_BASE
+i
].b
=(irq_handler
[i
]&0xffff0000)+PRESENT
+
198 for (j
= 0; j
< MAXIMUM_PROCESSORS
; j
++)
203 InitializeListHead(&IsrTable
[i
][j
].ListHead
);
204 KeInitializeSpinLock(&IsrTable
[i
][j
].Lock
);
205 IsrTable
[i
][j
].Count
= 0;
211 KeIRQTrapFrameToTrapFrame(PKIRQ_TRAPFRAME IrqTrapFrame
,
212 PKTRAP_FRAME TrapFrame
)
214 TrapFrame
->Gs
= (USHORT
)IrqTrapFrame
->Gs
;
215 TrapFrame
->Fs
= (USHORT
)IrqTrapFrame
->Fs
;
216 TrapFrame
->Es
= (USHORT
)IrqTrapFrame
->Es
;
217 TrapFrame
->Ds
= (USHORT
)IrqTrapFrame
->Ds
;
218 TrapFrame
->Eax
= IrqTrapFrame
->Eax
;
219 TrapFrame
->Ecx
= IrqTrapFrame
->Ecx
;
220 TrapFrame
->Edx
= IrqTrapFrame
->Edx
;
221 TrapFrame
->Ebx
= IrqTrapFrame
->Ebx
;
222 TrapFrame
->Esp
= IrqTrapFrame
->Esp
;
223 TrapFrame
->Ebp
= IrqTrapFrame
->Ebp
;
224 TrapFrame
->Esi
= IrqTrapFrame
->Esi
;
225 TrapFrame
->Edi
= IrqTrapFrame
->Edi
;
226 TrapFrame
->Eip
= IrqTrapFrame
->Eip
;
227 TrapFrame
->Cs
= IrqTrapFrame
->Cs
;
228 TrapFrame
->Eflags
= IrqTrapFrame
->Eflags
;
232 KeTrapFrameToIRQTrapFrame(PKTRAP_FRAME TrapFrame
,
233 PKIRQ_TRAPFRAME IrqTrapFrame
)
235 IrqTrapFrame
->Gs
= TrapFrame
->Gs
;
236 IrqTrapFrame
->Fs
= TrapFrame
->Fs
;
237 IrqTrapFrame
->Es
= TrapFrame
->Es
;
238 IrqTrapFrame
->Ds
= TrapFrame
->Ds
;
239 IrqTrapFrame
->Eax
= TrapFrame
->Eax
;
240 IrqTrapFrame
->Ecx
= TrapFrame
->Ecx
;
241 IrqTrapFrame
->Edx
= TrapFrame
->Edx
;
242 IrqTrapFrame
->Ebx
= TrapFrame
->Ebx
;
243 IrqTrapFrame
->Esp
= TrapFrame
->Esp
;
244 IrqTrapFrame
->Ebp
= TrapFrame
->Ebp
;
245 IrqTrapFrame
->Esi
= TrapFrame
->Esi
;
246 IrqTrapFrame
->Edi
= TrapFrame
->Edi
;
247 IrqTrapFrame
->Eip
= TrapFrame
->Eip
;
248 IrqTrapFrame
->Cs
= TrapFrame
->Cs
;
249 IrqTrapFrame
->Eflags
= TrapFrame
->Eflags
;
253 KiInterruptDispatch2 (ULONG vector
, KIRQL old_level
)
255 * FUNCTION: Calls all the interrupt handlers for a given irq.
257 * vector - The number of the vector to call handlers for.
258 * old_level - The irql of the processor when the irq took place.
259 * NOTES: Must be called at DIRQL.
265 PISR_TABLE CurrentIsr
;
267 DPRINT("I(0x%.08x, 0x%.08x)\n", vector
, old_level
);
270 * Iterate the list until one of the isr tells us its device interrupted
272 CurrentIsr
= &IsrTable
[vector
- IRQ_BASE
][(ULONG
)KeGetCurrentProcessorNumber()];
274 KiAcquireSpinLock(&CurrentIsr
->Lock
);
277 current
= CurrentIsr
->ListHead
.Flink
;
279 while (current
!= &CurrentIsr
->ListHead
)
281 isr
= CONTAINING_RECORD(current
,KINTERRUPT
,Entry
);
282 oldlvl
= KeAcquireInterruptSpinLock(isr
);
283 if (isr
->ServiceRoutine(isr
, isr
->ServiceContext
))
285 KeReleaseInterruptSpinLock(isr
, oldlvl
);
288 KeReleaseInterruptSpinLock(isr
, oldlvl
);
289 current
= current
->Flink
;
291 KiReleaseSpinLock(&CurrentIsr
->Lock
);
295 KiInterruptDispatch (ULONG vector
, PKIRQ_TRAPFRAME Trapframe
)
297 * FUNCTION: Calls the irq specific handler for an irq
299 * irq = IRQ that has interrupted
303 KTRAP_FRAME KernelTrapFrame
;
304 PKTHREAD CurrentThread
;
305 PKTRAP_FRAME OldTrapFrame
=NULL
;
308 * At this point we have interrupts disabled, nothing has been done to
312 KeGetCurrentPrcb()->InterruptCount
++;
315 * Notify the rest of the kernel of the raised irq level. For the
316 * default HAL this will send an EOI to the PIC and alter the IRQL.
318 if (!HalBeginSystemInterrupt (vector
,
328 * NOTE: Only higher priority interrupts will get through
330 Ke386EnableInterrupts();
333 if (VECTOR2IRQ(vector
) == 0)
335 KeIRQTrapFrameToTrapFrame(Trapframe
, &KernelTrapFrame
);
336 KeUpdateSystemTime(&KernelTrapFrame
, old_level
);
342 * Actually call the ISR.
344 KiInterruptDispatch2(vector
, old_level
);
348 * End the system interrupt.
350 Ke386DisableInterrupts();
352 HalEndSystemInterrupt (old_level
, 0);
354 if (old_level
==PASSIVE_LEVEL
&& Trapframe
->Cs
!= KERNEL_CS
)
356 CurrentThread
= KeGetCurrentThread();
357 if (CurrentThread
!=NULL
&& CurrentThread
->Alerted
[1])
359 DPRINT("PID: %d, TID: %d CS %04x/%04x\n",
360 ((PETHREAD
)CurrentThread
)->ThreadsProcess
->UniqueProcessId
,
361 ((PETHREAD
)CurrentThread
)->Cid
.UniqueThread
,
363 CurrentThread
->TrapFrame
? CurrentThread
->TrapFrame
->Cs
: 0);
364 if (CurrentThread
->TrapFrame
== NULL
)
366 OldTrapFrame
= CurrentThread
->TrapFrame
;
367 KeIRQTrapFrameToTrapFrame(Trapframe
, &KernelTrapFrame
);
368 CurrentThread
->TrapFrame
= &KernelTrapFrame
;
371 Ke386EnableInterrupts();
372 KiDeliverApc(KernelMode
, NULL
, NULL
);
373 Ke386DisableInterrupts();
375 ASSERT(KeGetCurrentThread() == CurrentThread
);
376 if (CurrentThread
->TrapFrame
== &KernelTrapFrame
)
378 KeTrapFrameToIRQTrapFrame(&KernelTrapFrame
, Trapframe
);
379 CurrentThread
->TrapFrame
= OldTrapFrame
;
389 PLIST_ENTRY current_entry
;
394 for (i
=0;i
<NR_IRQS
;i
++)
397 KeRaiseIrql(VECTOR2IRQL(i
+ IRQ_BASE
),&oldlvl
);
399 for (j
=0; j
< KeNumberProcessors
; j
++)
401 KiAcquireSpinLock(&IsrTable
[i
][j
].Lock
);
403 current_entry
= IsrTable
[i
][j
].ListHead
.Flink
;
404 current
= CONTAINING_RECORD(current_entry
,KINTERRUPT
,Entry
);
405 while (current_entry
!=&(IsrTable
[i
][j
].ListHead
))
407 if (printed
== FALSE
)
410 DPRINT("For irq %x:\n",i
);
412 DPRINT(" Isr %x\n",current
);
413 current_entry
= current_entry
->Flink
;
414 current
= CONTAINING_RECORD(current_entry
,KINTERRUPT
,Entry
);
416 KiReleaseSpinLock(&IsrTable
[i
][j
].Lock
);
426 KeConnectInterrupt(PKINTERRUPT InterruptObject
)
428 KIRQL oldlvl
,synch_oldlvl
;
429 PKINTERRUPT ListHead
;
431 PISR_TABLE CurrentIsr
;
434 DPRINT("KeConnectInterrupt()\n");
436 Vector
= InterruptObject
->Vector
;
438 if (Vector
< IRQ_BASE
|| Vector
>= IRQ_BASE
+ NR_IRQS
)
443 ASSERT (InterruptObject
->ProcessorNumber
< KeNumberProcessors
);
445 KeSetSystemAffinityThread(1 << InterruptObject
->ProcessorNumber
);
447 CurrentIsr
= &IsrTable
[Vector
][(ULONG
)InterruptObject
->ProcessorNumber
];
449 KeRaiseIrql(VECTOR2IRQL(Vector
+ IRQ_BASE
),&oldlvl
);
450 KiAcquireSpinLock(&CurrentIsr
->Lock
);
453 * Check if the vector is already in use that we can share it
455 if (!IsListEmpty(&CurrentIsr
->ListHead
))
457 ListHead
= CONTAINING_RECORD(CurrentIsr
->ListHead
.Flink
,KINTERRUPT
,Entry
);
458 if (InterruptObject
->Shareable
== FALSE
|| ListHead
->Shareable
==FALSE
)
460 KiReleaseSpinLock(&CurrentIsr
->Lock
);
462 KeRevertToUserAffinityThread();
467 synch_oldlvl
= KeAcquireInterruptSpinLock(InterruptObject
);
469 DPRINT("%x %x\n",CurrentIsr
->ListHead
.Flink
, CurrentIsr
->ListHead
.Blink
);
471 Result
= HalEnableSystemInterrupt(Vector
+ IRQ_BASE
, InterruptObject
->Irql
, InterruptObject
->InterruptMode
);
474 InsertTailList(&CurrentIsr
->ListHead
,&InterruptObject
->Entry
);
475 DPRINT("%x %x\n",InterruptObject
->Entry
.Flink
, InterruptObject
->Entry
.Blink
);
478 KeReleaseInterruptSpinLock(InterruptObject
, synch_oldlvl
);
481 * Release the table spinlock
483 KiReleaseSpinLock(&CurrentIsr
->Lock
);
488 KeRevertToUserAffinityThread();
498 KeDisconnectInterrupt(PKINTERRUPT InterruptObject
)
500 * FUNCTION: Releases a drivers isr
502 * InterruptObject = isr to release
505 KIRQL oldlvl
,synch_oldlvl
;
506 PISR_TABLE CurrentIsr
;
508 DPRINT("KeDisconnectInterrupt\n");
510 ASSERT (InterruptObject
->ProcessorNumber
< KeNumberProcessors
);
512 KeSetSystemAffinityThread(1 << InterruptObject
->ProcessorNumber
);
514 CurrentIsr
= &IsrTable
[InterruptObject
->Vector
- IRQ_BASE
][(ULONG
)InterruptObject
->ProcessorNumber
];
516 KeRaiseIrql(VECTOR2IRQL(InterruptObject
->Vector
),&oldlvl
);
517 KiAcquireSpinLock(&CurrentIsr
->Lock
);
519 synch_oldlvl
= KeAcquireInterruptSpinLock(InterruptObject
);
521 RemoveEntryList(&InterruptObject
->Entry
);
522 if (IsListEmpty(&CurrentIsr
->ListHead
))
524 HalDisableSystemInterrupt(InterruptObject
->Vector
, 0);
526 KeReleaseInterruptSpinLock(InterruptObject
, synch_oldlvl
);
529 * Release the table spinlock
531 KiReleaseSpinLock(&CurrentIsr
->Lock
);
534 KeRevertToUserAffinityThread();
543 KeInitializeInterrupt(PKINTERRUPT InterruptObject
,
544 PKSERVICE_ROUTINE ServiceRoutine
,
545 PVOID ServiceContext
,
546 PKSPIN_LOCK SpinLock
,
549 KIRQL SynchronizeIrql
,
550 KINTERRUPT_MODE InterruptMode
,
552 CHAR ProcessorNumber
,
553 BOOLEAN FloatingSave
)
555 InterruptObject
->ServiceRoutine
= ServiceRoutine
;
556 InterruptObject
->ServiceContext
= ServiceContext
;
557 InterruptObject
->ActualLock
= SpinLock
;
558 InterruptObject
->Vector
= Vector
;
559 InterruptObject
->Irql
= Irql
;
560 InterruptObject
->SynchLevel
= SynchronizeIrql
;
561 InterruptObject
->InterruptMode
= InterruptMode
;
562 InterruptObject
->Shareable
= ShareVector
;
563 InterruptObject
->ProcessorNumber
= ProcessorNumber
;
564 InterruptObject
->FloatingSave
= FloatingSave
;
567 VOID
KePrintInterruptStatistic(VOID
)
571 for (j
= 0; j
< KeNumberProcessors
; j
++)
573 DPRINT1("CPU%d:\n", j
);
574 for (i
= 0; i
< NR_IRQS
; i
++)
576 if (IsrTable
[i
][j
].Count
)
578 DPRINT1(" Irq %x(%d): %d\n", i
, VECTOR2IRQ(i
+ IRQ_BASE
), IsrTable
[i
][j
].Count
);