reactos操作系统实现(97)

在这个函数里,又继续地调用内核的两个函数KiConnectVectorToInterruptHalEnableSystemInterrupt来处理。

#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  }

你可能感兴趣的:(react)