调用函数IoConnectInterrupt来设置键中断处理函数。
#028 Status = IoConnectInterrupt(
#029 &PortDeviceExtension->KeyboardInterrupt.Object,
#030 i8042KbdInterruptService,
#031 DeviceExtension, &PortDeviceExtension->SpinLock,
#032 PortDeviceExtension->KeyboardInterrupt.Vector, PortDeviceExtension->KeyboardInterrupt.Dirql, DirqlMax,
#033 PortDeviceExtension->KeyboardInterrupt.InterruptMode, PortDeviceExtension->KeyboardInterrupt.ShareInterrupt,
#034 PortDeviceExtension->KeyboardInterrupt.Affinity, FALSE);
#035 if (!NT_SUCCESS(Status))
#036 {
#037 WARN_(I8042PRT, "IoConnectInterrupt() failed with status 0x%08x/n", Status);
#038 return Status;
#039 }
#040
设置最大的请求级别。
#041 if (DirqlMax == PortDeviceExtension->KeyboardInterrupt.Dirql)
#042 PortDeviceExtension->HighestDIRQLInterrupt = PortDeviceExtension->KeyboardInterrupt.Object;
设置键盘已经初始化。
#043 PortDeviceExtension->Flags |= KEYBOARD_INITIALIZED;
#044 return STATUS_SUCCESS;
#045 }
其实是调用IO管理器里的中断设置函数IoConnectInterrupt,实现如下:
#001 NTSTATUS
#002 NTAPI
#003 IoConnectInterrupt(OUT PKINTERRUPT *InterruptObject,
#004 IN PKSERVICE_ROUTINE ServiceRoutine,
#005 IN PVOID ServiceContext,
#006 IN PKSPIN_LOCK SpinLock,
#007 IN ULONG Vector,
#008 IN KIRQL Irql,
#009 IN KIRQL SynchronizeIrql,
#010 IN KINTERRUPT_MODE InterruptMode,
#011 IN BOOLEAN ShareVector,
#012 IN KAFFINITY ProcessorEnableMask,
#013 IN BOOLEAN FloatingSave)
#014 {
InterruptObject是返回中断处理对象。
ServiceRoutine是中断调用函数。
ServiceContext是中断调用函数使用的参数。
SpinLock是访问输入参数的自旋锁。
Vector是PNP管理器分配的中断号。
Irql是中断请求优先级。
SynchronizeIrql是同步请求优先级。
InterruptMode是中断的模式。
ShareVector是中断资源是否共享。
ProcessorEnableMask是中断允许发生的处理器。
FloatingSave指明是否保存浮点堆栈。
#015 PKINTERRUPT Interrupt;
#016 PKINTERRUPT InterruptUsed;
#017 PIO_INTERRUPT IoInterrupt;
#018 PKSPIN_LOCK SpinLockUsed;
#019 BOOLEAN FirstRun;
#020 CCHAR Count = 0;
#021 KAFFINITY Affinity;
#022 PAGED_CODE();
#023
假定失败的返回结果。
#024 /* Assume failure */
#025 *InterruptObject = NULL;
#026
获取处理器位。
#027 /* Get the affinity */
#028 Affinity = ProcessorEnableMask & KeActiveProcessors;
#029 while (Affinity)
#030 {
#031 /* Increase count */
#032 if (Affinity & 1) Count++;
#033 Affinity >>= 1;
#034 }
#035
确保这个CPU有中断响应。
#036 /* Make sure we have a valid CPU count */
#037 if (!Count) return STATUS_INVALID_PARAMETER;
#038
分配一个IO中断结构。
#039 /* Allocate the array of I/O Interrupts */
#040 IoInterrupt = ExAllocatePoolWithTag(NonPagedPool,
#041 (Count - 1) * sizeof(KINTERRUPT) +
#042 sizeof(IO_INTERRUPT),
#043 TAG_KINTERRUPT);
#044 if (!IoInterrupt) return STATUS_INSUFFICIENT_RESOURCES;
#045
如果驱动程序传入自旋锁,就使用驱动程序的,否则就使用内核分配的。
#046 /* Select which Spinlock to use */
#047 SpinLockUsed = SpinLock ? SpinLock : &IoInterrupt->SpinLock;
#048
设置返回的中断对象。
#049 /* We first start with a built-in Interrupt inside the I/O Structure */
#050 *InterruptObject = &IoInterrupt->FirstInterrupt;
#051 Interrupt = (PKINTERRUPT)(IoInterrupt + 1);
#052 FirstRun = TRUE;
#053
初始化中断对象结构。
#054 /* Start with a fresh structure */
#055 RtlZeroMemory(IoInterrupt, sizeof(IO_INTERRUPT));
#056
开始创建所有CPU的中断。
#057 /* Now create all the interrupts */
#058 Affinity = ProcessorEnableMask & KeActiveProcessors;
#059 for (Count = 0; Affinity; Count++, Affinity >>= 1)
#060 {
检查这个CPU是否有中断设置。
#061 /* Check if it's enabled for this CPU */
#062 if (Affinity & 1)
#063 {
是否第一个CPU中断设置。
#064 /* Check which one we will use */
#065 InterruptUsed = FirstRun ? &IoInterrupt->FirstInterrupt : Interrupt;
#066
设置中断对象。
#067 /* Initialize it */
#068 KeInitializeInterrupt(InterruptUsed,
#069 ServiceRoutine,
#070 ServiceContext,
#071 SpinLockUsed,
#072 Vector,
#073 Irql,
#074 SynchronizeIrql,
#075 InterruptMode,
#076 ShareVector,
#077 Count,
#078 FloatingSave);
#079
#080 /* Connect it */
调用内核函数KeConnectInterrupt设置中断。
#081 if (!KeConnectInterrupt(InterruptUsed))
#082 {
#083 /* Check how far we got */
#084 if (FirstRun)
#085 {
#086 /* We failed early so just free this */
#087 ExFreePool(IoInterrupt);
#088 }
#089 else
#090 {
如果没有设置中断成功,就返回出错。
#091 /* Far enough, so disconnect everything */
#092 IoDisconnectInterrupt(&IoInterrupt->FirstInterrupt);
#093 }
#094
#095 /* And fail */
#096 return STATUS_INVALID_PARAMETER;
#097 }
#098
设置第一个中断响应,已经设置完成。
#099 /* Now we've used up our First Run */
#100 if (FirstRun)
#101 {
#102 FirstRun = FALSE;
#103 }
#104 else
#105 {
把其它CPU的中断放到队列后面。
#106 /* Move on to the next one */
#107 IoInterrupt->Interrupt[(UCHAR)Count] = Interrupt++;
#108 }
#109 }
#110 }
#111
#112 /* Return Success */
#113 return STATUS_SUCCESS;
#114 }
在这个函数主要到两个内核函数来设置中断,它就是函数KeInitializeInterrupt 和KeConnectInterrupt。下来分析函数KeConnectInterrupt实现,看看它是怎么样把中断服务器与内核连接在一起的,如下:
#001 BOOLEAN
#002 NTAPI
#003 KeConnectInterrupt(IN PKINTERRUPT Interrupt)
#004 {
#005 BOOLEAN Connected, Error, Status;
#006 KIRQL Irql, OldIrql;
#007 UCHAR Number;
#008 ULONG Vector;
#009 DISPATCH_INFO Dispatch;
#010
从中断里获取中断号所在CPU、中断向量、中断优先级。
#011 /* Get data from interrupt */
#012 Number = Interrupt->Number;
#013 Vector = Interrupt->Vector;
#014 Irql = Interrupt->Irql;
#015
检查参数是否有效。
#016 /* Validate the settings */
#017 if ((Irql > HIGH_LEVEL) ||
#018 (Number >= KeNumberProcessors) ||
#019 (Interrupt->SynchronizeIrql < Irql) ||
#020 (Interrupt->FloatingSave))
#021 {
#022 return FALSE;
#023 }
#024
设置缺省状态。
#025 /* Set defaults */
#026 Connected = FALSE;
#027 Error = FALSE;
#028
设置起作用的CPU。
#029 /* Set the system affinity and acquire the dispatcher lock */
#030 KeSetSystemAffinityThread(1 << Number);
#031 OldIrql = KiAcquireDispatcherLock();
#032
检查中断是否已经连接到系统里。
#033 /* Check if it's already been connected */
#034 if (!Interrupt->Connected)
#035 {
如果没有连接,就查找分发信息。
#036 /* Get vector dispatching information */
#037 KiGetVectorDispatch(Vector, &Dispatch);
#038
如果分发器也没有连接这个中断。
#039 /* Check if the vector is already connected */
#040 if (Dispatch.Type == NoConnect)
#041 {
开始连接这个中断处理函数。
#042 /* Do the connection */
#043 Interrupt->Connected = Connected = TRUE;
#044
#045 /* Initialize the list */
#046 InitializeListHead(&Interrupt->InterruptListEntry);
#047
连接中断处理,并启动这个中断。
#048 /* Connect and enable the interrupt */
#049 KiConnectVectorToInterrupt(Interrupt, NormalConnect);
#050 Status = HalEnableSystemInterrupt(Vector, Irql, Interrupt->Mode);
#051 if (!Status) Error = TRUE;
#052 }
#053 else if ((Dispatch.Type != UnknownConnect) &&
#054 (Interrupt->ShareVector) &&
#055 (Dispatch.Interrupt->ShareVector) &&
#056 (Dispatch.Interrupt->Mode == Interrupt->Mode))
#057 {
这里是处理共享中断的情况。
#058 /* The vector is shared and the interrupts are compatible */
#059 ASSERT(FALSE); // FIXME: NOT YET SUPPORTED/TESTED
#060 Interrupt->Connected = Connected = TRUE;
#061 ASSERT(Irql <= SYNCH_LEVEL);
#062
是否为第一个连接。
#063 /* Check if this is the first chain */
#064 if (Dispatch.Type != ChainConnect)
#065 {
#066 /* Setup the chainned handler */
#067 KiConnectVectorToInterrupt(Dispatch.Interrupt, ChainConnect);
#068 }
#069
把这个中断放到中断响应列表里。
#070 /* Insert into the interrupt list */
#071 InsertTailList(&Dispatch.Interrupt->InterruptListEntry,
#072 &Interrupt->InterruptListEntry);
#073 }
#074 }
#075
#076 /* Unlock the dispatcher and revert affinity */
#077 KiReleaseDispatcherLock(OldIrql);
#078 KeRevertToUserAffinityThread();
#079
如果连接失败,就准备下一次连接。
#080 /* Check if we failed while trying to connect */
#081 if ((Connected) && (Error))
#082 {
#083 DPRINT1("HalEnableSystemInterrupt failed/n");
#084 KeDisconnectInterrupt(Interrupt);
#085 Connected = FALSE;
#086 }
#087
#088 /* Return to caller */
#089 return Connected;
#090 }