-/* $Id$
- *
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/ke/i386/irq.c
- * PURPOSE: IRQ handling
- *
- * PROGRAMMERS: David Welch (welch@mcmail.com)
- */
-
/*
- * NOTE: In general the PIC interrupt priority facilities are used to
- * preserve the NT IRQL semantics, global interrupt disables are only used
- * to keep the PIC in a consistent state
- *
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL - See COPYING in the top level directory
+ * FILE: ntoskrnl/ke/i386/irq.c
+ * PURPOSE: Manages the Kernel's IRQ support for external drivers,
+ * for the purpopses of connecting, disconnecting and setting
+ * up ISRs for drivers. The backend behind the Io* Interrupt
+ * routines.
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
-/* INCLUDES ****************************************************************/
+/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
-#include <../hal/halx86/include/halirq.h>
-#include <../hal/halx86/include/mps.h>
-
#define NDEBUG
-#include <internal/debug.h>
-
-extern KDPC KiExpireTimerDpc;
-extern ULONG KiMaximumDpcQueueDepth;
-extern ULONG KiMinimumDpcRate;
-extern ULONG KiAdjustDpcThreshold;
-extern ULONG KiIdealDpcRate;
-extern LONG KiTickOffset;
-extern ULONG KeMaximumIncrement;
-extern ULONG KeMinimumIncrement;
-extern ULONG KeTimeAdjustment;
-extern BOOLEAN KiClockSetupComplete;
-
-/* GLOBALS *****************************************************************/
-
-/* Interrupt handler list */
-
-#ifdef CONFIG_SMP
-
-#define INT_NAME2(intnum) KiUnexpectedInterrupt##intnum
-
-#define BUILD_INTERRUPT_HANDLER(intnum) \
-VOID INT_NAME2(intnum)(VOID);
-
-#define D(x,y) \
- BUILD_INTERRUPT_HANDLER(x##y)
-
-#define D16(x) \
- D(x,0) D(x,1) D(x,2) D(x,3) \
- D(x,4) D(x,5) D(x,6) D(x,7) \
- D(x,8) D(x,9) D(x,A) D(x,B) \
- D(x,C) D(x,D) D(x,E) D(x,F)
-
-D16(3) D16(4) D16(5) D16(6)
-D16(7) D16(8) D16(9) D16(A)
-D16(B) D16(C) D16(D) D16(E)
-D16(F)
-
-#define L(x,y) \
- (ULONG)& INT_NAME2(x##y)
-
-#define L16(x) \
- L(x,0), L(x,1), L(x,2), L(x,3), \
- L(x,4), L(x,5), L(x,6), L(x,7), \
- L(x,8), L(x,9), L(x,A), L(x,B), \
- L(x,C), L(x,D), L(x,E), L(x,F)
-
-static ULONG irq_handler[ROUND_UP(NR_IRQS, 16)] = {
- L16(3), L16(4), L16(5), L16(6),
- L16(7), L16(8), L16(9), L16(A),
- L16(B), L16(C), L16(D), L16(E)
-};
+#include <debug.h>
-#undef L
-#undef L16
-#undef D
-#undef D16
+/* DEPRECATED ****************************************************************/
-#else /* CONFIG_SMP */
+#include <../hal/halx86/include/halirq.h>
+#include <../hal/halx86/include/mps.h>
void irq_handler_0(void);
void irq_handler_1(void);
(int)&irq_handler_15,
};
-#endif /* CONFIG_SMP */
-
/*
* PURPOSE: Object describing each isr
* NOTE: The data in this table is only modified at passsive level but can
}
ISR_TABLE, *PISR_TABLE;
-#ifdef CONFIG_SMP
-static ISR_TABLE IsrTable[NR_IRQS][MAXIMUM_PROCESSORS];
-#else
-static ISR_TABLE IsrTable[NR_IRQS][1];
-#endif
+static ISR_TABLE IsrTable[NR_IRQS];
#define TAG_ISR_LOCK TAG('I', 'S', 'R', 'L')
-/* FUNCTIONS ****************************************************************/
-
#define PRESENT (0x8000)
#define I486_INTERRUPT_GATE (0xe00)
NTAPI
KeInitInterrupts (VOID)
{
- int i, j;
-
+ int i;
/*
* Setup the IDT entries to point to the interrupt handlers
((IDT_DESCRIPTOR*)&KiIdt[IRQ_BASE+i])->a=(irq_handler[i]&0xffff)+(KGDT_R0_CODE<<16);
((IDT_DESCRIPTOR*)&KiIdt[IRQ_BASE+i])->b=(irq_handler[i]&0xffff0000)+PRESENT+
I486_INTERRUPT_GATE;
-#ifdef CONFIG_SMP
- for (j = 0; j < MAXIMUM_PROCESSORS; j++)
-#else
- j = 0;
-#endif
{
- InitializeListHead(&IsrTable[i][j].ListHead);
- KeInitializeSpinLock(&IsrTable[i][j].Lock);
- IsrTable[i][j].Count = 0;
+ InitializeListHead(&IsrTable[i].ListHead);
+ KeInitializeSpinLock(&IsrTable[i].Lock);
+ IsrTable[i].Count = 0;
}
}
}
KIRQL oldlvl;
PISR_TABLE CurrentIsr;
- DPRINT("I(0x%.08x, 0x%.08x)\n", vector, old_level);
-
/*
* Iterate the list until one of the isr tells us its device interrupted
*/
- CurrentIsr = &IsrTable[vector - IRQ_BASE][(ULONG)KeGetCurrentProcessorNumber()];
+ CurrentIsr = &IsrTable[vector - IRQ_BASE];
KiAcquireSpinLock(&CurrentIsr->Lock);
* At this point we have interrupts disabled, nothing has been done to
* the PIC.
*/
-
KeGetCurrentPrcb()->InterruptCount++;
/*
CurrentThread = KeGetCurrentThread();
if (CurrentThread!=NULL && CurrentThread->ApcState.UserApcPending)
{
- DPRINT("PID: %d, TID: %d CS %04x/%04x\n",
- ((PETHREAD)CurrentThread)->ThreadsProcess->UniqueProcessId,
- ((PETHREAD)CurrentThread)->Cid.UniqueThread,
- Trapframe->Cs,
- CurrentThread->TrapFrame ? CurrentThread->TrapFrame->SegCs : 0);
ASSERT (CurrentThread->TrapFrame);
_enable();
{
HalEndSystemInterrupt (old_level, 0);
}
+}
+/* PRIVATE FUNCTIONS *********************************************************/
+
+VOID
+NTAPI
+KiGetVectorDispatch(IN ULONG Vector,
+ IN PDISPATCH_INFO Dispatch)
+{
+ PKINTERRUPT_ROUTINE Handler;
+ ULONG Current;
+
+ /* Setup the unhandled dispatch */
+ Dispatch->NoDispatch = (PVOID)(((ULONG_PTR)&KiStartUnexpectedRange) +
+ (Vector - PRIMARY_VECTOR_BASE) *
+ KiUnexpectedEntrySize);
+
+ /* Setup the handlers */
+ Dispatch->InterruptDispatch = KiInterruptDispatch;
+ Dispatch->FloatingDispatch = NULL; // Floating Interrupts are not supported
+ Dispatch->ChainedDispatch = KiChainedDispatch;
+ Dispatch->FlatDispatch = NULL;
+
+ /* Get the current handler */
+ Current = ((((PKIPCR)KeGetPcr())->IDT[Vector].ExtendedOffset << 16)
+ & 0xFFFF0000) |
+ (((PKIPCR)KeGetPcr())->IDT[Vector].Offset & 0xFFFF);
+
+ /* Set the interrupt */
+ Dispatch->Interrupt = CONTAINING_RECORD(Current,
+ KINTERRUPT,
+ DispatchCode);
+
+ /* Check what this interrupt is connected to */
+ if ((PKINTERRUPT_ROUTINE)Current == Dispatch->NoDispatch)
+ {
+ /* Not connected */
+ Dispatch->Type = NoConnect;
+ }
+ else
+ {
+ /* Get the handler */
+ Handler = Dispatch->Interrupt->DispatchAddress;
+ if (Handler == Dispatch->ChainedDispatch)
+ {
+ /* It's a chained interrupt */
+ Dispatch->Type = ChainConnect;
+ }
+ else if ((Handler == Dispatch->InterruptDispatch) ||
+ (Handler == Dispatch->FloatingDispatch))
+ {
+ /* It's unchained */
+ Dispatch->Type = NormalConnect;
+ }
+ else
+ {
+ /* Unknown */
+ Dispatch->Type = UnknownConnect;
+ }
+ }
}
-static VOID
-KeDumpIrqList(VOID)
+VOID
+NTAPI
+KiConnectVectorToInterrupt(IN PKINTERRUPT Interrupt,
+ IN CONNECT_TYPE Type)
{
- PKINTERRUPT current;
- PLIST_ENTRY current_entry;
- LONG i, j;
- KIRQL oldlvl;
- BOOLEAN printed;
+ DISPATCH_INFO Dispatch;
+ PKINTERRUPT_ROUTINE Handler;
+ PULONG Patch = &Interrupt->DispatchCode[0];
- for (i=0;i<NR_IRQS;i++)
- {
- printed = FALSE;
- KeRaiseIrql(VECTOR2IRQL(i + IRQ_BASE),&oldlvl);
+ /* Get vector data */
+ KiGetVectorDispatch(Interrupt->Vector, &Dispatch);
- for (j=0; j < KeNumberProcessors; j++)
- {
- KiAcquireSpinLock(&IsrTable[i][j].Lock);
-
- current_entry = IsrTable[i][j].ListHead.Flink;
- current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry);
- while (current_entry!=&(IsrTable[i][j].ListHead))
- {
- if (printed == FALSE)
- {
- printed = TRUE;
- DPRINT("For irq %x:\n",i);
- }
- DPRINT(" Isr %x\n",current);
- current_entry = current_entry->Flink;
- current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry);
- }
- KiReleaseSpinLock(&IsrTable[i][j].Lock);
- }
- KeLowerIrql(oldlvl);
- }
+ /* Check if we're only disconnecting */
+ if (Type == NoConnect)
+ {
+ /* Set the handler to NoDispatch */
+ Handler = Dispatch.NoDispatch;
+ }
+ else
+ {
+ /* Get the right handler */
+ Handler = (Type == NormalConnect) ?
+ Dispatch.InterruptDispatch:
+ Dispatch.ChainedDispatch;
+ ASSERT(Interrupt->FloatingSave == FALSE);
+
+ /* Set the handler */
+ Interrupt->DispatchAddress = Handler;
+
+ /* Jump to the last 4 bytes */
+ Patch = (PULONG)((ULONG_PTR)Patch +
+ ((ULONG_PTR)&KiInterruptTemplateDispatch -
+ (ULONG_PTR)KiInterruptTemplate) - 4);
+
+ /* Apply the patch */
+ *Patch = (ULONG)((ULONG_PTR)Handler - ((ULONG_PTR)Patch + 4));
+
+ /* Now set the final handler address */
+ ASSERT(Dispatch.FlatDispatch == NULL);
+ Handler = (PVOID)&Interrupt->DispatchCode;
+ }
+
+ /* Set the pointer in the IDT */
+ ((PKIPCR)KeGetPcr())->IDT[Interrupt->Vector].ExtendedOffset =
+ (USHORT)(((ULONG_PTR)Handler >> 16) & 0xFFFF);
+ ((PKIPCR)KeGetPcr())->IDT[Interrupt->Vector].Offset =
+ (USHORT)PtrToUlong(Handler);
}
+/* PUBLIC FUNCTIONS **********************************************************/
+
/*
* @implemented
*/
-BOOLEAN
-STDCALL
-KeConnectInterrupt(PKINTERRUPT InterruptObject)
+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)
+{
+ ULONG i;
+ PULONG DispatchCode = &Interrupt->DispatchCode[0], Patch = DispatchCode;
+
+ /* Set the Interrupt Header */
+ Interrupt->Type = InterruptObject;
+ Interrupt->Size = sizeof(KINTERRUPT);
+
+ /* Check if we got a spinlock */
+ if (SpinLock)
+ {
+ /* Use the spinlock given to us */
+ Interrupt->ActualLock = SpinLock;
+ }
+ else
+ {
+ /* This means we'll be using the built-in one */
+ KeInitializeSpinLock(&Interrupt->SpinLock);
+ Interrupt->ActualLock = &Interrupt->SpinLock;
+ }
+
+ /* Set the other settings */
+ Interrupt->ServiceRoutine = ServiceRoutine;
+ Interrupt->ServiceContext = ServiceContext;
+ Interrupt->Vector = Vector;
+ Interrupt->Irql = Irql;
+ Interrupt->SynchronizeIrql = SynchronizeIrql;
+ Interrupt->Mode = InterruptMode;
+ Interrupt->ShareVector = ShareVector;
+ Interrupt->Number = ProcessorNumber;
+ Interrupt->FloatingSave = FloatingSave;
+
+ /* Loop the template in memory */
+ for (i = 0; i < KINTERRUPT_DISPATCH_CODES; i++)
+ {
+ /* Copy the dispatch code */
+ *DispatchCode++ = KiInterruptTemplate[i];
+ }
+
+ /* Jump to the last 4 bytes */
+ Patch = (PULONG)((ULONG_PTR)Patch +
+ ((ULONG_PTR)&KiInterruptTemplateObject -
+ (ULONG_PTR)KiInterruptTemplate) - 4);
+
+ /* Apply the patch */
+ *Patch = PtrToUlong(Interrupt);
+
+ /* Disconnect it at first */
+ Interrupt->Connected = FALSE;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+KeConnectInterrupt(IN PKINTERRUPT InterruptObject)
{
KIRQL oldlvl,synch_oldlvl;
PKINTERRUPT ListHead;
KeSetSystemAffinityThread(1 << InterruptObject->Number);
- CurrentIsr = &IsrTable[Vector][(ULONG)InterruptObject->Number];
+ CurrentIsr = &IsrTable[Vector];
KeRaiseIrql(VECTOR2IRQL(Vector + IRQ_BASE),&oldlvl);
KiAcquireSpinLock(&CurrentIsr->Lock);
synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject);
- DPRINT("%x %x\n",CurrentIsr->ListHead.Flink, CurrentIsr->ListHead.Blink);
-
Result = HalEnableSystemInterrupt(Vector + IRQ_BASE, InterruptObject->Irql, InterruptObject->Mode);
if (Result)
{
InsertTailList(&CurrentIsr->ListHead,&InterruptObject->InterruptListEntry);
- DPRINT("%x %x\n",InterruptObject->InterruptListEntry.Flink, InterruptObject->InterruptListEntry.Blink);
}
InterruptObject->Connected = TRUE;
KiReleaseSpinLock(&CurrentIsr->Lock);
KeLowerIrql(oldlvl);
- KeDumpIrqList();
-
KeRevertToUserAffinityThread();
return Result;
/*
* @implemented
- *
- * FUNCTION: Releases a drivers isr
- * ARGUMENTS:
- * InterruptObject = isr to release
*/
-BOOLEAN
-STDCALL
-KeDisconnectInterrupt(PKINTERRUPT InterruptObject)
+BOOLEAN
+NTAPI
+KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)
{
- KIRQL oldlvl,synch_oldlvl;
- PISR_TABLE CurrentIsr;
+ KIRQL OldIrql, Irql;
+ ULONG Vector;
+ DISPATCH_INFO Dispatch;
+ PKINTERRUPT NextInterrupt;
BOOLEAN State;
- DPRINT1("KeDisconnectInterrupt\n");
- ASSERT (InterruptObject->Number < KeNumberProcessors);
-
/* Set the affinity */
- KeSetSystemAffinityThread(1 << InterruptObject->Number);
-
- /* Get the ISR Tabe */
- CurrentIsr = &IsrTable[InterruptObject->Vector - IRQ_BASE]
- [(ULONG)InterruptObject->Number];
+ KeSetSystemAffinityThread(1 << Interrupt->Number);
- /* Raise IRQL to required level and lock table */
- KeRaiseIrql(VECTOR2IRQL(InterruptObject->Vector),&oldlvl);
- KiAcquireSpinLock(&CurrentIsr->Lock);
+ /* Lock the dispatcher */
+ OldIrql = KiAcquireDispatcherLock();
/* Check if it's actually connected */
- if ((State = InterruptObject->Connected))
+ State = Interrupt->Connected;
+ if (State)
{
- /* Lock the Interrupt */
- synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject);
+ /* Get the vector and IRQL */
+ Irql = Interrupt->Irql;
+ Vector = Interrupt->Vector;
- /* Remove this one, and check if all are gone */
- RemoveEntryList(&InterruptObject->InterruptListEntry);
- if (IsListEmpty(&CurrentIsr->ListHead))
+ /* Get vector dispatch data */
+ KiGetVectorDispatch(Vector, &Dispatch);
+
+ /* Check if it was chained */
+ if (Dispatch.Type == ChainConnect)
+ {
+ /* Check if the top-level interrupt is being removed */
+ ASSERT(Irql <= SYNCH_LEVEL);
+ if (Interrupt == Dispatch.Interrupt)
+ {
+ /* Get the next one */
+ Dispatch.Interrupt = CONTAINING_RECORD(Dispatch.Interrupt->
+ InterruptListEntry.Flink,
+ KINTERRUPT,
+ InterruptListEntry);
+
+ /* Reconnect it */
+ KiConnectVectorToInterrupt(Dispatch.Interrupt, ChainConnect);
+ }
+
+ /* Remove it */
+ RemoveEntryList(&Interrupt->InterruptListEntry);
+
+ /* Get the next one */
+ NextInterrupt = CONTAINING_RECORD(Dispatch.Interrupt->
+ InterruptListEntry.Flink,
+ KINTERRUPT,
+ InterruptListEntry);
+
+ /* Check if this is the only one left */
+ if (Dispatch.Interrupt == NextInterrupt)
+ {
+ /* Connect it in non-chained mode */
+ KiConnectVectorToInterrupt(Dispatch.Interrupt, NormalConnect);
+ }
+ }
+ else
{
- /* Completely Disable the Interrupt */
- HalDisableSystemInterrupt(InterruptObject->Vector, InterruptObject->Irql);
+ /* Only one left, disable and remove it */
+ HalDisableSystemInterrupt(Interrupt->Vector, Irql);
+ KiConnectVectorToInterrupt(Interrupt, NoConnect);
}
-
+
/* Disconnect it */
- InterruptObject->Connected = FALSE;
-
- /* Release the interrupt lock */
- KeReleaseInterruptSpinLock(InterruptObject, synch_oldlvl);
+ Interrupt->Connected = FALSE;
}
- /* Release the table spinlock */
- KiReleaseSpinLock(&CurrentIsr->Lock);
- KeLowerIrql(oldlvl);
- /* Go back to default affinity */
+ /* Unlock the dispatcher and revert affinity */
+ KiReleaseDispatcherLock(OldIrql);
KeRevertToUserAffinityThread();
-
- /* Return Old Interrupt State */
- return State;
-}
-
-/*
- * @implemented
- */
-VOID
-STDCALL
-KeInitializeInterrupt(PKINTERRUPT Interrupt,
- PKSERVICE_ROUTINE ServiceRoutine,
- PVOID ServiceContext,
- PKSPIN_LOCK SpinLock,
- ULONG Vector,
- KIRQL Irql,
- KIRQL SynchronizeIrql,
- KINTERRUPT_MODE InterruptMode,
- BOOLEAN ShareVector,
- CHAR ProcessorNumber,
- BOOLEAN FloatingSave)
-{
- /* Set the Interrupt Header */
- Interrupt->Type = InterruptObject;
- Interrupt->Size = sizeof(KINTERRUPT);
-
- /* Check if we got a spinlock */
- if (SpinLock)
- {
- Interrupt->ActualLock = SpinLock;
- }
- else
- {
- /* This means we'll be usin the built-in one */
- KeInitializeSpinLock(&Interrupt->SpinLock);
- Interrupt->ActualLock = &Interrupt->SpinLock;
- }
-
- /* Set the other settings */
- Interrupt->ServiceRoutine = ServiceRoutine;
- Interrupt->ServiceContext = ServiceContext;
- Interrupt->Vector = Vector;
- Interrupt->Irql = Irql;
- Interrupt->SynchronizeIrql = SynchronizeIrql;
- Interrupt->Mode = InterruptMode;
- Interrupt->ShareVector = ShareVector;
- Interrupt->Number = ProcessorNumber;
- Interrupt->FloatingSave = FloatingSave;
-
- /* Disconnect it at first */
- Interrupt->Connected = FALSE;
-}
-VOID KePrintInterruptStatistic(VOID)
-{
- LONG i, j;
-
- for (j = 0; j < KeNumberProcessors; j++)
- {
- DPRINT1("CPU%d:\n", j);
- for (i = 0; i < NR_IRQS; i++)
- {
- if (IsrTable[i][j].Count)
- {
- DPRINT1(" Irq %x(%d): %d\n", i, VECTOR2IRQ(i + IRQ_BASE), IsrTable[i][j].Count);
- }
- }
- }
+ /* Return to caller */
+ return State;
}
/* EOF */