/* * @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; }