/*
* @implemented
來看一下跟中斷對象有關的兩個對象:
typedef struct _IO_INTERRUPT
{
KINTERRUPT FirstInterrupt;
PKINTERRUPT Interrupt[MAXIMUM_PROCESSORS];
KSPIN_LOCK SpinLock;
} IO_INTERRUPT, *PIO_INTERRUPT;
typedef struct _KINTERRUPT
{
CSHORT Type;
CSHORT Size;
LIST_ENTRY InterruptListEntry;
PKSERVICE_ROUTINE ServiceRoutine;
#if (NTDDI_VERSION >= NTDDI_LONGHORN)
PKSERVICE_ROUTINE MessageServiceRoutine;
ULONG MessageIndex;
#endif
...
#if (NTDDI_VERSION >= NTDDI_LONGHORN)
ULONGLONG Rsvd1;
#endif
//指向INT_PROLOG代碼段位址
ULONG DispatchCode[KINTERRUPT_DISPATCH_CODES];
} KINTERRUPT, *PKINTERRUPT;
安裝中斷過程勢必配置設定一個中斷對象KINTERRUPT,對于單個CPU。
如果主機上有多個CPU,那就必須為每個CPU配置設定相同的
中斷對象,這樣,不同的CPU接到中斷信号後才能有相同
的處理過程。
如果有這麼多功能相同的卻離散分布的中斷對象,管理
起來比較麻煩,于是Reactos為這些具有相同處理過程的中斷對象
配置設定一個統一的管理對象_IO_INTERRUPT,把同一類中斷對象裝入到
這個_IO_INTERRUPT結構中去
如此看來_KINTERRUPT是實際的處理者,而_IO_INTERRUPT更像一個管理者
*/
NTSTATUS
NTAPI
IoConnectInterrupt(OUT PKINTERRUPT *InterruptObject,
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 KAFFINITY ProcessorEnableMask,
IN BOOLEAN FloatingSave)
{
PKINTERRUPT Interrupt;
PKINTERRUPT InterruptUsed;
//IO_INTERRUPT:具有相同中斷處理函數的CPU的集合
PIO_INTERRUPT IoInterrupt;
PKSPIN_LOCK SpinLockUsed;
BOOLEAN FirstRun = TRUE;
CCHAR Count = 0;
KAFFINITY Affinity;
PAGED_CODE();
/* Assume failure */
*InterruptObject = NULL;
/* Get the affinity */
Affinity = ProcessorEnableMask & KeActiveProcessors;
while (Affinity)
{
/* Increase count */
if (Affinity & 1) Count++;
Affinity >>= 1;
}
/* Make sure we have a valid CPU count */
if (!Count) return STATUS_INVALID_PARAMETER;
/* Allocate the array of I/O Interrupts */
/*
Count>1 針對多CPU的情況. struct _IO_INTERRUPT IoInterrupt是用于管理多CPU中斷處理的結構
IoInterrupt->KINTERRUPT[0]->ISR
->KINTERRUPT[1]->ISR
->KINTERRUPT[2]->ISR
這麼說,在SMP結構中調用一次IoConnectInterrupt就會為所有具有中斷處理能力的
CPU都安裝相同的中斷處理過程(即中斷對象)
*/
/*
主要是配置設定IO_INTERRUPT--中斷對象的管理者,其次才是在這個對象的尾部跟上諾幹
數量上和系統中具有該中斷處理能力的CPU的中斷對象
當本函數後面KeInitializeInterrupt/KeConnectInterrupt調用完成後,将這個中斷對象添加到
IO_INTERRUPT管理者中
*/
IoInterrupt = ExAllocatePoolWithTag(NonPagedPool,
(Count - 1) * sizeof(KINTERRUPT) +
sizeof(IO_INTERRUPT),
TAG_KINTERRUPT);
if (!IoInterrupt) return STATUS_INSUFFICIENT_RESOURCES;
/* Select which Spinlock to use */
SpinLockUsed = SpinLock ? SpinLock : &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 */
Affinity = ProcessorEnableMask & KeActiveProcessors;
//初始化IO_INTERRUPT中每個KINTERRUPT結構
for (Count = 0; Affinity; Count++, Affinity >>= 1)
{
/* Check if it's enabled for this CPU */
//Affinity & 1-->具有處理能力的CPU
if (Affinity & 1)
{
/* Check which one we will use */
InterruptUsed = FirstRun ? &IoInterrupt->FirstInterrupt : Interrupt;
/* Initialize it */
KeInitializeInterrupt(InterruptUsed,
ServiceRoutine,
ServiceContext,
SpinLockUsed,
Vector,
Irql,
SynchronizeIrql,
InterruptMode,
ShareVector,
Count,
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);
}
/* And fail */
return STATUS_INVALID_PARAMETER;
}
/* Now we've used up our First Run */
if (FirstRun)
{
//處理完FirstInterrupt,即将對其他CPU進行處理
FirstRun = FALSE;
}
else
{
/* Move on to the next one */
/*
前面針對多處理器配置設定了多個中斷處理對象,把經過處理的
KINTERRUPT結構加入到IoInterrupt管理機構中
(意即:這些CPU上已有這種中斷處理程式)
*/
IoInterrupt->Interrupt[(UCHAR)Count] = Interrupt++;
}
}
}
/* Return Success */
return STATUS_SUCCESS;
}