在这个函数里,又继续地调用内核的两个函数KiConnectVectorToInterrupt和HalEnableSystemInterrupt来处理。
#001 VOID
#002 NTAPI
#003 KiConnectVectorToInterrupt(IN PKINTERRUPT Interrupt,
#004 IN CONNECT_TYPE Type)
#005 {
#006 DISPATCH_INFO Dispatch;
#007 PKINTERRUPT_ROUTINE Handler;
#008 PULONG Patch = &Interrupt->DispatchCode[0];
#009
获取中断的分发信息,其实就是设置中断处理中间函数。
#010 /* Get vector data */
#011 KiGetVectorDispatch(Interrupt->Vector, &Dispatch);
#012
检查是否没有连接中断。
#013 /* Check if we're only disconnecting */
#014 if (Type == NoConnect)
#015 {
没有中断处理函数,就使用缺省的。
#016 /* Set the handler to NoDispatch */
#017 Handler = Dispatch.NoDispatch;
#018 }
#019 else
#020 {
根据中断是共享类型,还是普通类型,如果是共享就调用中断列表,否则就调用中断处理函数。
#021 /* Get the right handler */
#022 Handler = (Type == NormalConnect) ?
#023 Dispatch.InterruptDispatch:
#024 Dispatch.ChainedDispatch;
#025 ASSERT(Interrupt->FloatingSave == FALSE);
#026
设置中断处理的地址。
#027 /* Set the handler */
#028 Interrupt->DispatchAddress = Handler;
#029
这里将KiInterruptTemplateDispatch那里的jmp指令的跳转地址改写为Handler,至于这里为什么要用Handler的地址减去Patch再加4,那是因为这里是相对地址的跳转。所以是从当前指令来偏移的。
#030 /* Jump to the last 4 bytes */
#031 Patch = (PULONG)((ULONG_PTR)Patch +
#032 ((ULONG_PTR)&KiInterruptTemplateDispatch -
#033 (ULONG_PTR)KiInterruptTemplate) - 4);
#034
#035 /* Apply the patch */
#036 *Patch = (ULONG)((ULONG_PTR)Handler - ((ULONG_PTR)Patch + 4));
#037
#038 /* Now set the final handler address */
#039 ASSERT(Dispatch.FlatDispatch == NULL);
#040 Handler = (PVOID)&Interrupt->DispatchCode;
#041 }
#042
这里把中断处理函数设置到中断描述表里。
#043 /* Set the pointer in the IDT */
#044 ((PKIPCR)KeGetPcr())->IDT[Interrupt->Vector].ExtendedOffset =
#045 (USHORT)(((ULONG_PTR)Handler >> 16) & 0xFFFF);
#046 ((PKIPCR)KeGetPcr())->IDT[Interrupt->Vector].Offset =
#047 (USHORT)PtrToUlong(Handler);
#048 }
下面回过头来分析函数KeInitializeInterrupt的实现,因为这个初始化代码比较重要,看了它才明白怎么样实现中断连接,如下:
#001 VOID
#002 NTAPI
#003 KeInitializeInterrupt(IN PKINTERRUPT Interrupt,
#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 CHAR ProcessorNumber,
#013 IN BOOLEAN FloatingSave)
#014 {
#015 ULONG i;
#016 PULONG DispatchCode = &Interrupt->DispatchCode[0], Patch = DispatchCode;
#017
设置中断处理头部份。
#018 /* Set the Interrupt Header */
#019 Interrupt->Type = InterruptObject;
#020 Interrupt->Size = sizeof(KINTERRUPT);
#021
检查是否已经分配自旋锁。
#022 /* Check if we got a spinlock */
#023 if (SpinLock)
#024 {
#025 Interrupt->ActualLock = SpinLock;
#026 }
#027 else
#028 {
#029 /* This means we'll be usin the built-in one */
#030 KeInitializeSpinLock(&Interrupt->SpinLock);
#031 Interrupt->ActualLock = &Interrupt->SpinLock;
#032 }
#033
初始化中断结构相关的属性。
#034 /* Set the other settings */
#035 Interrupt->ServiceRoutine = ServiceRoutine;
#036 Interrupt->ServiceContext = ServiceContext;
#037 Interrupt->Vector = Vector;
#038 Interrupt->Irql = Irql;
#039 Interrupt->SynchronizeIrql = SynchronizeIrql;
#040 Interrupt->Mode = InterruptMode;
#041 Interrupt->ShareVector = ShareVector;
#042 Interrupt->Number = ProcessorNumber;
#043 Interrupt->FloatingSave = FloatingSave;
#044 Interrupt->TickCount = (ULONG)-1;
#045 Interrupt->DispatchCount = (ULONG)-1;
#046
拷贝中断处理函数的中间跳转代码。共有106x4个字节大小。
#047 /* Loop the template in memory */
#048 for (i = 0; i < KINTERRUPT_DISPATCH_CODES; i++)
#049 {
#050 /* Copy the dispatch code */
#051 *DispatchCode++ = KiInterruptTemplate[i];
#052 }
#053
检查这段中断处理代码是否合法。
#054 /* Sanity check */
#055 ASSERT((ULONG_PTR)&KiChainedDispatch2ndLvl -
#056 (ULONG_PTR)KiInterruptTemplate <= (KINTERRUPT_DISPATCH_CODES * 4));
#057
计算中断处理函数的最后4字节的位置,也就是模板代码里这一行:
mov edi, 0,相当于设置0这个参数,也就是把中断结构的指针保存edi寄存器里,以便后面跳转函数可以使用这个中断结构。
#058 /* Jump to the last 4 bytes */
#059 Patch = (PULONG)((ULONG_PTR)Patch +
#060 ((ULONG_PTR)&KiInterruptTemplateObject -
#061 (ULONG_PTR)KiInterruptTemplate) - 4);
#062
把实际中断结构指针保存在中断的模板代码里,以便中断发生时,就可以跳到相应的中断函数运行,并可以获取中断参数。
#063 /* Apply the patch */
#064 *Patch = PtrToUlong(Interrupt);
#065
#066 /* Disconnect it at first */
#067 Interrupt->Connected = FALSE;
#068 }