reactos操作系统实现(97)
在这个函数里,又继续地调用内核的两个函数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} (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |