From d1258e99faf96c2743b421277de2de267031bd81 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Wed, 22 Jun 2005 23:10:15 +0000 Subject: [PATCH] Fix definition of KINTERRUPT in ROS headers so that moving to NDK will be easier. Also fix KeDisconnectInterrupt to return the old state instead of VOID, and re-write the I/O Interrupt code to work with an array and first object for better speed svn path=/trunk/; revision=16229 --- reactos/include/ntos/kefuncs.h | 2 +- reactos/include/ntos/zwtypes.h | 52 +++++-- reactos/ntoskrnl/io/irq.c | 258 ++++++++++++++++++++------------- reactos/ntoskrnl/ke/i386/irq.c | 160 ++++++++++++-------- reactos/ntoskrnl/ke/spinlock.c | 3 +- 5 files changed, 293 insertions(+), 182 deletions(-) diff --git a/reactos/include/ntos/kefuncs.h b/reactos/include/ntos/kefuncs.h index 17c7febeafc..33af624033b 100644 --- a/reactos/include/ntos/kefuncs.h +++ b/reactos/include/ntos/kefuncs.h @@ -62,7 +62,7 @@ BOOLEAN STDCALL KeConnectInterrupt( PKINTERRUPT InterruptObject); -VOID STDCALL +BOOLEAN STDCALL KeDisconnectInterrupt( PKINTERRUPT InterruptObject); diff --git a/reactos/include/ntos/zwtypes.h b/reactos/include/ntos/zwtypes.h index e166f72b46c..ce9e2f84360 100755 --- a/reactos/include/ntos/zwtypes.h +++ b/reactos/include/ntos/zwtypes.h @@ -1781,22 +1781,48 @@ typedef struct _LPC_PORT_BASIC_INFORMATION } LPC_PORT_BASIC_INFORMATION, * PLPC_PORT_BASIC_INFORMATION; +#if 0 typedef struct _KINTERRUPT { - ULONG Vector; - KAFFINITY ProcessorEnableMask; - KSPIN_LOCK SpinLock; - PKSPIN_LOCK ActualLock; - BOOLEAN Shareable; - BOOLEAN FloatingSave; - CHAR ProcessorNumber; - PKSERVICE_ROUTINE ServiceRoutine; - PVOID ServiceContext; - LIST_ENTRY Entry; - KIRQL Irql; - KIRQL SynchLevel; - KINTERRUPT_MODE InterruptMode; + ULONG Vector; // Idem + KAFFINITY ProcessorEnableMask; // not needed + KSPIN_LOCK SpinLock; // Idem + PKSPIN_LOCK ActualLock; // Idem + BOOLEAN Shareable; // ShareVector + BOOLEAN FloatingSave; // Idem + CHAR ProcessorNumber; // Number + PKSERVICE_ROUTINE ServiceRoutine; // Idem + PVOID ServiceContext; // Idem + LIST_ENTRY Entry; // InteruptListEntry + KIRQL Irql; // Irql + KIRQL SynchLevel; // SynchronizeIrql + KINTERRUPT_MODE InterruptMode; // Mode } KINTERRUPT; +#endif + +typedef struct _KINTERRUPT +{ + CSHORT Type; + CSHORT Size; + LIST_ENTRY InterruptListEntry; + PKSERVICE_ROUTINE ServiceRoutine; + PVOID ServiceContext; + KSPIN_LOCK SpinLock; + ULONG TickCount; + PKSPIN_LOCK ActualLock; + PVOID DispatchAddress; + ULONG Vector; + KIRQL Irql; + KIRQL SynchronizeIrql; + BOOLEAN FloatingSave; + BOOLEAN Connected; + CHAR Number; + UCHAR ShareVector; + KINTERRUPT_MODE Mode; + ULONG ServiceCount; + ULONG DispatchCount; + ULONG DispatchCode[106]; +} KINTERRUPT, *PKINTERRUPT; #ifndef __USE_W32API diff --git a/reactos/ntoskrnl/io/irq.c b/reactos/ntoskrnl/io/irq.c index d80f7c00986..7f9ebb24c22 100644 --- a/reactos/ntoskrnl/io/irq.c +++ b/reactos/ntoskrnl/io/irq.c @@ -14,23 +14,16 @@ #define NDEBUG #include +/* TYPES ********************************************************************/ +typedef struct _IO_INTERRUPT +{ + KINTERRUPT FirstInterrupt; + PKINTERRUPT Interrupt[MAXIMUM_PROCESSORS]; + KSPIN_LOCK SpinLock; +} IO_INTERRUPT, *PIO_INTERRUPT; + /* FUNCTIONS *****************************************************************/ -/* - * @implemented - */ -NTSTATUS STDCALL -IoConnectInterrupt(PKINTERRUPT* InterruptObject, - PKSERVICE_ROUTINE ServiceRoutine, - PVOID ServiceContext, - PKSPIN_LOCK SpinLock, - ULONG Vector, - KIRQL Irql, - KIRQL SynchronizeIrql, - KINTERRUPT_MODE InterruptMode, - BOOLEAN ShareVector, - KAFFINITY ProcessorEnableMask, - BOOLEAN FloatingSave) /* * FUNCTION: Registers a driver's isr to be called when its device interrupts * ARGUMENTS: @@ -57,106 +50,163 @@ IoConnectInterrupt(PKINTERRUPT* InterruptObject, * the isr runs. Must be false for x86 drivers * RETURNS: Status * IRQL: PASSIVE_LEVEL - */ -{ - PKINTERRUPT Interrupt; - ULONG i, count; - - ASSERT_IRQL(PASSIVE_LEVEL); - - DPRINT("IoConnectInterrupt(Vector %x)\n",Vector); - - ProcessorEnableMask &= ((1 << KeNumberProcessors) - 1); - - if (ProcessorEnableMask == 0) - { - return STATUS_INVALID_PARAMETER; - } - - for (i = 0, count = 0; i < KeNumberProcessors; i++) - { - if (ProcessorEnableMask & (1 << i)) - { - count++; - } - } - /* - * Initialize interrupt object - */ - Interrupt=ExAllocatePoolWithTag(NonPagedPool,count*sizeof(KINTERRUPT), - TAG_KINTERRUPT); - if (Interrupt==NULL) - { - return(STATUS_INSUFFICIENT_RESOURCES); - } - - if (SpinLock == NULL) - { - SpinLock = &Interrupt[0].SpinLock; - KeInitializeSpinLock(SpinLock); - } - - Interrupt[0].ProcessorEnableMask = ProcessorEnableMask; - - for (i = 0, count = 0; i < KeNumberProcessors; i++) - { - if (ProcessorEnableMask & (1 << i)) - { - KeInitializeInterrupt(&Interrupt[count], - ServiceRoutine, - ServiceContext, - SpinLock, - Vector, - Irql, - SynchronizeIrql, - InterruptMode, - ShareVector, - i, - FloatingSave); - if (!KeConnectInterrupt(&Interrupt[count])) - { - for (i = 0; i < count; i++) - { - if (ProcessorEnableMask & (1 << i)) - { - KeDisconnectInterrupt(&Interrupt[i]); - } - } - ExFreePool(Interrupt); - return STATUS_INVALID_PARAMETER; - } - count++; - } - } - - *InterruptObject = Interrupt; - - return(STATUS_SUCCESS); -} - - -/* + * * @implemented */ -VOID STDCALL -IoDisconnectInterrupt(PKINTERRUPT InterruptObject) +NTSTATUS +STDCALL +IoConnectInterrupt(PKINTERRUPT* InterruptObject, + PKSERVICE_ROUTINE ServiceRoutine, + PVOID ServiceContext, + PKSPIN_LOCK SpinLock, + ULONG Vector, + KIRQL Irql, + KIRQL SynchronizeIrql, + KINTERRUPT_MODE InterruptMode, + BOOLEAN ShareVector, + KAFFINITY ProcessorEnableMask, + BOOLEAN FloatingSave) +{ + PKINTERRUPT Interrupt; + PKINTERRUPT InterruptUsed; + PIO_INTERRUPT IoInterrupt; + PKSPIN_LOCK SpinLockUsed; + BOOLEAN FirstRun = TRUE; + ULONG i, count; + + PAGED_CODE(); + + DPRINT1("IoConnectInterrupt(Vector %x)\n",Vector); + + /* Convert the Mask */ + ProcessorEnableMask &= ((1 << KeNumberProcessors) - 1); + + /* Make sure at least one CPU is on it */ + if (!ProcessorEnableMask) return STATUS_INVALID_PARAMETER; + + /* Determine the allocation */ + for (i = 0, count = 0; i < KeNumberProcessors; i++) + { + if (ProcessorEnableMask & (1 << i)) count++; + } + + /* Allocate the array of I/O Interrupts */ + IoInterrupt = ExAllocatePoolWithTag(NonPagedPool, + (count - 1)* sizeof(KINTERRUPT) + + sizeof(IO_INTERRUPT), + TAG_KINTERRUPT); + if (!Interrupt) return(STATUS_INSUFFICIENT_RESOURCES); + + /* Select which Spinlock to use */ + if (SpinLock) + { + SpinLockUsed = SpinLock; + } + else + { + SpinLockUsed = &IoInterrupt->SpinLock; + } + + /* We first start with a built-in Interrupt inside the I/O Structure */ + *InterruptObject = &IoInterrupt->FirstInterrupt; + Interrupt = (PKINTERRUPT)(IoInterrupt + 1); + FirstRun = TRUE; + + /* Start with a fresh structure */ + RtlZeroMemory(IoInterrupt, sizeof(IO_INTERRUPT)); + + /* Now create all the interrupts */ + for (i = 0; i < KeNumberProcessors; i++) + { + /* Check if it's enabled for this CPU */ + if (ProcessorEnableMask & (1 << i)) + { + /* Check which one we will use */ + InterruptUsed = FirstRun ? &IoInterrupt->FirstInterrupt : Interrupt; + + /* Initialize it */ + KeInitializeInterrupt(InterruptUsed, + ServiceRoutine, + ServiceContext, + SpinLockUsed, + Vector, + Irql, + SynchronizeIrql, + InterruptMode, + ShareVector, + i, + FloatingSave); + + /* Connect it */ + if (!KeConnectInterrupt(InterruptUsed)) + { + /* Check how far we got */ + if (FirstRun) + { + /* We failed early so just free this */ + ExFreePool(IoInterrupt); + } + else + { + /* Far enough, so disconnect everything */ + IoDisconnectInterrupt(&IoInterrupt->FirstInterrupt); + } + return STATUS_INVALID_PARAMETER; + } + + /* Now we've used up our First Run */ + if (FirstRun) + { + FirstRun = FALSE; + } + else + { + /* Move on to the next one */ + IoInterrupt->Interrupt[i] = Interrupt++; + } + } + } + + /* Return Success */ + return STATUS_SUCCESS; +} + /* * FUNCTION: Releases a drivers isr * ARGUMENTS: * InterruptObject = isr to release + * + * @implemented */ -{ - ULONG i, count; +VOID +STDCALL +IoDisconnectInterrupt(PKINTERRUPT InterruptObject) - for (i = 0, count = 0; i < KeNumberProcessors; i++) +{ + ULONG i; + PIO_INTERRUPT IoInterrupt; + + PAGED_CODE(); + + /* Get the I/O Interrupt */ + IoInterrupt = CONTAINING_RECORD(InterruptObject, + IO_INTERRUPT, + FirstInterrupt); + + /* Disconnect the first one */ + KeDisconnectInterrupt(&IoInterrupt->FirstInterrupt); + + /* Now disconnect the others */ + for (i = 0; i < KeNumberProcessors; i++) { - if (InterruptObject[0].ProcessorEnableMask & (1 << i)) + if (IoInterrupt->Interrupt[i]) { - KeDisconnectInterrupt(&InterruptObject[count]); - count++; - } + KeDisconnectInterrupt(&InterruptObject[i]); + } } - ExFreePool(InterruptObject); + + /* Free the I/O Interrupt */ + ExFreePool(IoInterrupt); } /* EOF */ diff --git a/reactos/ntoskrnl/ke/i386/irq.c b/reactos/ntoskrnl/ke/i386/irq.c index 59bbf0feed9..5b7280429a6 100644 --- a/reactos/ntoskrnl/ke/i386/irq.c +++ b/reactos/ntoskrnl/ke/i386/irq.c @@ -278,7 +278,7 @@ KiInterruptDispatch2 (ULONG vector, KIRQL old_level) while (current != &CurrentIsr->ListHead) { - isr = CONTAINING_RECORD(current,KINTERRUPT,Entry); + isr = CONTAINING_RECORD(current,KINTERRUPT,InterruptListEntry); oldlvl = KeAcquireInterruptSpinLock(isr); if (isr->ServiceRoutine(isr, isr->ServiceContext)) { @@ -401,7 +401,7 @@ KeDumpIrqList(VOID) KiAcquireSpinLock(&IsrTable[i][j].Lock); current_entry = IsrTable[i][j].ListHead.Flink; - current = CONTAINING_RECORD(current_entry,KINTERRUPT,Entry); + current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry); while (current_entry!=&(IsrTable[i][j].ListHead)) { if (printed == FALSE) @@ -411,7 +411,7 @@ KeDumpIrqList(VOID) } DPRINT(" Isr %x\n",current); current_entry = current_entry->Flink; - current = CONTAINING_RECORD(current_entry,KINTERRUPT,Entry); + current = CONTAINING_RECORD(current_entry,KINTERRUPT,InterruptListEntry); } KiReleaseSpinLock(&IsrTable[i][j].Lock); } @@ -422,7 +422,8 @@ KeDumpIrqList(VOID) /* * @implemented */ -BOOLEAN STDCALL +BOOLEAN +STDCALL KeConnectInterrupt(PKINTERRUPT InterruptObject) { KIRQL oldlvl,synch_oldlvl; @@ -440,11 +441,11 @@ KeConnectInterrupt(PKINTERRUPT InterruptObject) Vector -= IRQ_BASE; - ASSERT (InterruptObject->ProcessorNumber < KeNumberProcessors); + ASSERT (InterruptObject->Number < KeNumberProcessors); - KeSetSystemAffinityThread(1 << InterruptObject->ProcessorNumber); + KeSetSystemAffinityThread(1 << InterruptObject->Number); - CurrentIsr = &IsrTable[Vector][(ULONG)InterruptObject->ProcessorNumber]; + CurrentIsr = &IsrTable[Vector][(ULONG)InterruptObject->Number]; KeRaiseIrql(VECTOR2IRQL(Vector + IRQ_BASE),&oldlvl); KiAcquireSpinLock(&CurrentIsr->Lock); @@ -454,8 +455,8 @@ KeConnectInterrupt(PKINTERRUPT InterruptObject) */ if (!IsListEmpty(&CurrentIsr->ListHead)) { - ListHead = CONTAINING_RECORD(CurrentIsr->ListHead.Flink,KINTERRUPT,Entry); - if (InterruptObject->Shareable == FALSE || ListHead->Shareable==FALSE) + ListHead = CONTAINING_RECORD(CurrentIsr->ListHead.Flink,KINTERRUPT,InterruptListEntry); + if (InterruptObject->ShareVector == FALSE || ListHead->ShareVector==FALSE) { KiReleaseSpinLock(&CurrentIsr->Lock); KeLowerIrql(oldlvl); @@ -468,13 +469,14 @@ KeConnectInterrupt(PKINTERRUPT InterruptObject) DPRINT("%x %x\n",CurrentIsr->ListHead.Flink, CurrentIsr->ListHead.Blink); - Result = HalEnableSystemInterrupt(Vector + IRQ_BASE, InterruptObject->Irql, InterruptObject->InterruptMode); + Result = HalEnableSystemInterrupt(Vector + IRQ_BASE, InterruptObject->Irql, InterruptObject->Mode); if (Result) { - InsertTailList(&CurrentIsr->ListHead,&InterruptObject->Entry); - DPRINT("%x %x\n",InterruptObject->Entry.Flink, InterruptObject->Entry.Blink); + InsertTailList(&CurrentIsr->ListHead,&InterruptObject->InterruptListEntry); + DPRINT("%x %x\n",InterruptObject->InterruptListEntry.Flink, InterruptObject->Entry.Blink); } + InterruptObject->Connected = TRUE; KeReleaseInterruptSpinLock(InterruptObject, synch_oldlvl); /* @@ -490,78 +492,112 @@ KeConnectInterrupt(PKINTERRUPT InterruptObject) return Result; } - /* * @implemented - */ -VOID STDCALL -KeDisconnectInterrupt(PKINTERRUPT InterruptObject) -/* + * * FUNCTION: Releases a drivers isr * ARGUMENTS: * InterruptObject = isr to release */ +BOOLEAN +STDCALL +KeDisconnectInterrupt(PKINTERRUPT InterruptObject) { - KIRQL oldlvl,synch_oldlvl; - PISR_TABLE CurrentIsr; + KIRQL oldlvl,synch_oldlvl; + PISR_TABLE CurrentIsr; + BOOLEAN State; - DPRINT("KeDisconnectInterrupt\n"); + DPRINT1("KeDisconnectInterrupt\n"); + ASSERT (InterruptObject->Number < KeNumberProcessors); - ASSERT (InterruptObject->ProcessorNumber < KeNumberProcessors); + /* Set the affinity */ + KeSetSystemAffinityThread(1 << InterruptObject->Number); - KeSetSystemAffinityThread(1 << InterruptObject->ProcessorNumber); + /* Get the ISR Tabe */ + CurrentIsr = &IsrTable[InterruptObject->Vector - IRQ_BASE] + [(ULONG)InterruptObject->Number]; - CurrentIsr = &IsrTable[InterruptObject->Vector - IRQ_BASE][(ULONG)InterruptObject->ProcessorNumber]; + /* Raise IRQL to required level and lock table */ + KeRaiseIrql(VECTOR2IRQL(InterruptObject->Vector),&oldlvl); + KiAcquireSpinLock(&CurrentIsr->Lock); - KeRaiseIrql(VECTOR2IRQL(InterruptObject->Vector),&oldlvl); - KiAcquireSpinLock(&CurrentIsr->Lock); + /* Check if it's actually connected */ + if ((State = InterruptObject->Connected)) + { + /* Lock the Interrupt */ + synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject); - synch_oldlvl = KeAcquireInterruptSpinLock(InterruptObject); + /* Remove this one, and check if all are gone */ + RemoveEntryList(&InterruptObject->InterruptListEntry); + if (IsListEmpty(&CurrentIsr->ListHead)) + { + /* Completely Disable the Interrupt */ + HalDisableSystemInterrupt(InterruptObject->Vector, InterruptObject->Irql); + } + + /* Disconnect it */ + InterruptObject->Connected = FALSE; + + /* Release the interrupt lock */ + KeReleaseInterruptSpinLock(InterruptObject, synch_oldlvl); + } + /* Release the table spinlock */ + KiReleaseSpinLock(&CurrentIsr->Lock); + KeLowerIrql(oldlvl); - RemoveEntryList(&InterruptObject->Entry); - if (IsListEmpty(&CurrentIsr->ListHead)) - { - HalDisableSystemInterrupt(InterruptObject->Vector, 0); - } - KeReleaseInterruptSpinLock(InterruptObject, synch_oldlvl); - - /* - * Release the table spinlock - */ - KiReleaseSpinLock(&CurrentIsr->Lock); - KeLowerIrql(oldlvl); - - KeRevertToUserAffinityThread(); + /* Go back to default affinity */ + KeRevertToUserAffinityThread(); + + /* Return Old Interrupt State */ + return State; } - /* * @implemented */ VOID STDCALL -KeInitializeInterrupt(PKINTERRUPT InterruptObject, - PKSERVICE_ROUTINE ServiceRoutine, - PVOID ServiceContext, - PKSPIN_LOCK SpinLock, - ULONG Vector, - KIRQL Irql, - KIRQL SynchronizeIrql, - KINTERRUPT_MODE InterruptMode, - BOOLEAN ShareVector, - CHAR ProcessorNumber, - BOOLEAN FloatingSave) +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) { - InterruptObject->ServiceRoutine = ServiceRoutine; - InterruptObject->ServiceContext = ServiceContext; - InterruptObject->ActualLock = SpinLock; - InterruptObject->Vector = Vector; - InterruptObject->Irql = Irql; - InterruptObject->SynchLevel = SynchronizeIrql; - InterruptObject->InterruptMode = InterruptMode; - InterruptObject->Shareable = ShareVector; - InterruptObject->ProcessorNumber = ProcessorNumber; - InterruptObject->FloatingSave = 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) diff --git a/reactos/ntoskrnl/ke/spinlock.c b/reactos/ntoskrnl/ke/spinlock.c index 969d4fa3711..59d249229a1 100644 --- a/reactos/ntoskrnl/ke/spinlock.c +++ b/reactos/ntoskrnl/ke/spinlock.c @@ -62,8 +62,7 @@ KeAcquireInterruptSpinLock( { KIRQL oldIrql; - //KeRaiseIrql(Interrupt->SynchronizeIrql, &oldIrql); - KeRaiseIrql(Interrupt->SynchLevel, &oldIrql); + KeRaiseIrql(Interrupt->SynchronizeIrql, &oldIrql); KiAcquireSpinLock(Interrupt->ActualLock); return oldIrql; }