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 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值