- Cleanup more code in the deprecated IRQ implementation and use the newer implementations oF KeInitializeInterrupt and KeDisconnectInterrupt. Will allow easier debugging oF the HAL IRQ regression with the new, unused implementation.

svn path=/trunk/; revision=24910
This commit is contained in:
Alex Ionescu 2006-11-28 15:52:54 +00:00
parent 54306c43a2
commit 84348d0f29

View file

@ -1,87 +1,25 @@
/* $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 * PROJECT: ReactOS Kernel
* preserve the NT IRQL semantics, global interrupt disables are only used * LICENSE: GPL - See COPYING in the top level directory
* to keep the PIC in a consistent state * 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 <ntoskrnl.h>
#define NDEBUG
#include <debug.h>
/* DEPRECATED ****************************************************************/
#include <../hal/halx86/include/halirq.h> #include <../hal/halx86/include/halirq.h>
#include <../hal/halx86/include/mps.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)
};
#undef L
#undef L16
#undef D
#undef D16
#else /* CONFIG_SMP */
void irq_handler_0(void); void irq_handler_0(void);
void irq_handler_1(void); void irq_handler_1(void);
void irq_handler_2(void); void irq_handler_2(void);
@ -119,8 +57,6 @@ static unsigned int irq_handler[NR_IRQS]=
(int)&irq_handler_15, (int)&irq_handler_15,
}; };
#endif /* CONFIG_SMP */
/* /*
* PURPOSE: Object describing each isr * PURPOSE: Object describing each isr
* NOTE: The data in this table is only modified at passsive level but can * NOTE: The data in this table is only modified at passsive level but can
@ -135,16 +71,10 @@ typedef struct
} }
ISR_TABLE, *PISR_TABLE; ISR_TABLE, *PISR_TABLE;
#ifdef CONFIG_SMP static ISR_TABLE IsrTable[NR_IRQS];
static ISR_TABLE IsrTable[NR_IRQS][MAXIMUM_PROCESSORS];
#else
static ISR_TABLE IsrTable[NR_IRQS][1];
#endif
#define TAG_ISR_LOCK TAG('I', 'S', 'R', 'L') #define TAG_ISR_LOCK TAG('I', 'S', 'R', 'L')
/* FUNCTIONS ****************************************************************/
#define PRESENT (0x8000) #define PRESENT (0x8000)
#define I486_INTERRUPT_GATE (0xe00) #define I486_INTERRUPT_GATE (0xe00)
@ -153,8 +83,7 @@ INIT_FUNCTION
NTAPI NTAPI
KeInitInterrupts (VOID) KeInitInterrupts (VOID)
{ {
int i, j; int i;
/* /*
* Setup the IDT entries to point to the interrupt handlers * Setup the IDT entries to point to the interrupt handlers
@ -164,15 +93,10 @@ KeInitInterrupts (VOID)
((IDT_DESCRIPTOR*)&KiIdt[IRQ_BASE+i])->a=(irq_handler[i]&0xffff)+(KGDT_R0_CODE<<16); ((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+ ((IDT_DESCRIPTOR*)&KiIdt[IRQ_BASE+i])->b=(irq_handler[i]&0xffff0000)+PRESENT+
I486_INTERRUPT_GATE; I486_INTERRUPT_GATE;
#ifdef CONFIG_SMP
for (j = 0; j < MAXIMUM_PROCESSORS; j++)
#else
j = 0;
#endif
{ {
InitializeListHead(&IsrTable[i][j].ListHead); InitializeListHead(&IsrTable[i].ListHead);
KeInitializeSpinLock(&IsrTable[i][j].Lock); KeInitializeSpinLock(&IsrTable[i].Lock);
IsrTable[i][j].Count = 0; IsrTable[i].Count = 0;
} }
} }
} }
@ -192,12 +116,10 @@ KiInterruptDispatch2 (ULONG vector, KIRQL old_level)
KIRQL oldlvl; KIRQL oldlvl;
PISR_TABLE CurrentIsr; 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 * 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); KiAcquireSpinLock(&CurrentIsr->Lock);
@ -234,7 +156,6 @@ KiInterruptDispatch3 (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
* At this point we have interrupts disabled, nothing has been done to * At this point we have interrupts disabled, nothing has been done to
* the PIC. * the PIC.
*/ */
KeGetCurrentPrcb()->InterruptCount++; KeGetCurrentPrcb()->InterruptCount++;
/* /*
@ -274,11 +195,6 @@ KiInterruptDispatch3 (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
CurrentThread = KeGetCurrentThread(); CurrentThread = KeGetCurrentThread();
if (CurrentThread!=NULL && CurrentThread->ApcState.UserApcPending) 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); ASSERT (CurrentThread->TrapFrame);
_enable(); _enable();
@ -294,52 +210,192 @@ KiInterruptDispatch3 (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
{ {
HalEndSystemInterrupt (old_level, 0); HalEndSystemInterrupt (old_level, 0);
} }
} }
static VOID /* PRIVATE FUNCTIONS *********************************************************/
KeDumpIrqList(VOID)
VOID
NTAPI
KiGetVectorDispatch(IN ULONG Vector,
IN PDISPATCH_INFO Dispatch)
{ {
PKINTERRUPT current; PKINTERRUPT_ROUTINE Handler;
PLIST_ENTRY current_entry; ULONG Current;
LONG i, j;
KIRQL oldlvl;
BOOLEAN printed;
for (i=0;i<NR_IRQS;i++) /* Setup the unhandled dispatch */
{ Dispatch->NoDispatch = (PVOID)(((ULONG_PTR)&KiStartUnexpectedRange) +
printed = FALSE; (Vector - PRIMARY_VECTOR_BASE) *
KeRaiseIrql(VECTOR2IRQL(i + IRQ_BASE),&oldlvl); KiUnexpectedEntrySize);
for (j=0; j < KeNumberProcessors; j++) /* Setup the handlers */
{ Dispatch->InterruptDispatch = KiInterruptDispatch;
KiAcquireSpinLock(&IsrTable[i][j].Lock); Dispatch->FloatingDispatch = NULL; // Floating Interrupts are not supported
Dispatch->ChainedDispatch = KiChainedDispatch;
Dispatch->FlatDispatch = NULL;
current_entry = IsrTable[i][j].ListHead.Flink; /* Get the current handler */
current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry); Current = ((((PKIPCR)KeGetPcr())->IDT[Vector].ExtendedOffset << 16)
while (current_entry!=&(IsrTable[i][j].ListHead)) & 0xFFFF0000) |
{ (((PKIPCR)KeGetPcr())->IDT[Vector].Offset & 0xFFFF);
if (printed == FALSE)
{ /* Set the interrupt */
printed = TRUE; Dispatch->Interrupt = CONTAINING_RECORD(Current,
DPRINT("For irq %x:\n",i); KINTERRUPT,
} DispatchCode);
DPRINT(" Isr %x\n",current);
current_entry = current_entry->Flink; /* Check what this interrupt is connected to */
current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry); if ((PKINTERRUPT_ROUTINE)Current == Dispatch->NoDispatch)
} {
KiReleaseSpinLock(&IsrTable[i][j].Lock); /* Not connected */
} Dispatch->Type = NoConnect;
KeLowerIrql(oldlvl); }
} 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;
}
}
}
VOID
NTAPI
KiConnectVectorToInterrupt(IN PKINTERRUPT Interrupt,
IN CONNECT_TYPE Type)
{
DISPATCH_INFO Dispatch;
PKINTERRUPT_ROUTINE Handler;
PULONG Patch = &Interrupt->DispatchCode[0];
/* Get vector data */
KiGetVectorDispatch(Interrupt->Vector, &Dispatch);
/* 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
*/
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 * @implemented
*/ */
BOOLEAN BOOLEAN
STDCALL NTAPI
KeConnectInterrupt(PKINTERRUPT InterruptObject) KeConnectInterrupt(IN PKINTERRUPT InterruptObject)
{ {
KIRQL oldlvl,synch_oldlvl; KIRQL oldlvl,synch_oldlvl;
PKINTERRUPT ListHead; PKINTERRUPT ListHead;
@ -360,7 +416,7 @@ KeConnectInterrupt(PKINTERRUPT InterruptObject)
KeSetSystemAffinityThread(1 << InterruptObject->Number); KeSetSystemAffinityThread(1 << InterruptObject->Number);
CurrentIsr = &IsrTable[Vector][(ULONG)InterruptObject->Number]; CurrentIsr = &IsrTable[Vector];
KeRaiseIrql(VECTOR2IRQL(Vector + IRQ_BASE),&oldlvl); KeRaiseIrql(VECTOR2IRQL(Vector + IRQ_BASE),&oldlvl);
KiAcquireSpinLock(&CurrentIsr->Lock); KiAcquireSpinLock(&CurrentIsr->Lock);
@ -382,13 +438,10 @@ KeConnectInterrupt(PKINTERRUPT InterruptObject)
synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject); synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject);
DPRINT("%x %x\n",CurrentIsr->ListHead.Flink, CurrentIsr->ListHead.Blink);
Result = HalEnableSystemInterrupt(Vector + IRQ_BASE, InterruptObject->Irql, InterruptObject->Mode); Result = HalEnableSystemInterrupt(Vector + IRQ_BASE, InterruptObject->Irql, InterruptObject->Mode);
if (Result) if (Result)
{ {
InsertTailList(&CurrentIsr->ListHead,&InterruptObject->InterruptListEntry); InsertTailList(&CurrentIsr->ListHead,&InterruptObject->InterruptListEntry);
DPRINT("%x %x\n",InterruptObject->InterruptListEntry.Flink, InterruptObject->InterruptListEntry.Blink);
} }
InterruptObject->Connected = TRUE; InterruptObject->Connected = TRUE;
@ -400,8 +453,6 @@ KeConnectInterrupt(PKINTERRUPT InterruptObject)
KiReleaseSpinLock(&CurrentIsr->Lock); KiReleaseSpinLock(&CurrentIsr->Lock);
KeLowerIrql(oldlvl); KeLowerIrql(oldlvl);
KeDumpIrqList();
KeRevertToUserAffinityThread(); KeRevertToUserAffinityThread();
return Result; return Result;
@ -409,127 +460,84 @@ KeConnectInterrupt(PKINTERRUPT InterruptObject)
/* /*
* @implemented * @implemented
*
* FUNCTION: Releases a drivers isr
* ARGUMENTS:
* InterruptObject = isr to release
*/ */
BOOLEAN BOOLEAN
STDCALL NTAPI
KeDisconnectInterrupt(PKINTERRUPT InterruptObject) KeDisconnectInterrupt(IN PKINTERRUPT Interrupt)
{ {
KIRQL oldlvl,synch_oldlvl; KIRQL OldIrql, Irql;
PISR_TABLE CurrentIsr; ULONG Vector;
DISPATCH_INFO Dispatch;
PKINTERRUPT NextInterrupt;
BOOLEAN State; BOOLEAN State;
DPRINT1("KeDisconnectInterrupt\n");
ASSERT (InterruptObject->Number < KeNumberProcessors);
/* Set the affinity */ /* Set the affinity */
KeSetSystemAffinityThread(1 << InterruptObject->Number); KeSetSystemAffinityThread(1 << Interrupt->Number);
/* Get the ISR Tabe */ /* Lock the dispatcher */
CurrentIsr = &IsrTable[InterruptObject->Vector - IRQ_BASE] OldIrql = KiAcquireDispatcherLock();
[(ULONG)InterruptObject->Number];
/* Raise IRQL to required level and lock table */
KeRaiseIrql(VECTOR2IRQL(InterruptObject->Vector),&oldlvl);
KiAcquireSpinLock(&CurrentIsr->Lock);
/* Check if it's actually connected */ /* Check if it's actually connected */
if ((State = InterruptObject->Connected)) State = Interrupt->Connected;
if (State)
{ {
/* Lock the Interrupt */ /* Get the vector and IRQL */
synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject); Irql = Interrupt->Irql;
Vector = Interrupt->Vector;
/* Remove this one, and check if all are gone */ /* Get vector dispatch data */
RemoveEntryList(&InterruptObject->InterruptListEntry); KiGetVectorDispatch(Vector, &Dispatch);
if (IsListEmpty(&CurrentIsr->ListHead))
/* Check if it was chained */
if (Dispatch.Type == ChainConnect)
{ {
/* Completely Disable the Interrupt */ /* Check if the top-level interrupt is being removed */
HalDisableSystemInterrupt(InterruptObject->Vector, InterruptObject->Irql); ASSERT(Irql <= SYNCH_LEVEL);
} if (Interrupt == Dispatch.Interrupt)
{
/* Disconnect it */ /* Get the next one */
InterruptObject->Connected = FALSE; Dispatch.Interrupt = CONTAINING_RECORD(Dispatch.Interrupt->
InterruptListEntry.Flink,
/* Release the interrupt lock */ KINTERRUPT,
KeReleaseInterruptSpinLock(InterruptObject, synch_oldlvl); InterruptListEntry);
}
/* Release the table spinlock */
KiReleaseSpinLock(&CurrentIsr->Lock);
KeLowerIrql(oldlvl);
/* Go back to default affinity */ /* 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
{
/* Only one left, disable and remove it */
HalDisableSystemInterrupt(Interrupt->Vector, Irql);
KiConnectVectorToInterrupt(Interrupt, NoConnect);
}
/* Disconnect it */
Interrupt->Connected = FALSE;
}
/* Unlock the dispatcher and revert affinity */
KiReleaseDispatcherLock(OldIrql);
KeRevertToUserAffinityThread(); KeRevertToUserAffinityThread();
/* Return Old Interrupt State */ /* Return to caller */
return 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);
}
}
}
}
/* EOF */ /* EOF */