在x86体系结构上禁用/启用中断

时间:2019-02-06 10:32:52

标签: x86 kernel driver interrupt netbsd

我正在将NetBSD 5.1用于x86系统。在研究一些与驱动程序相关的代码时,我发现我们使用 splraise spllower 来阻止或允许中断。我在互联网上搜索了一些机制,以了解这些机制在现实中是如何工作的。没有得到任何真正的信息。

当我反汇编时,我得到了机制,但仍然不明白所有这些汇编指令如何产生结果。我个人知道x86指令,但不了解整个过程是如何工作的。

需要您的帮助来了解x86系统的原理。我了解我们需要禁用中断启用(IE)位,但是该程序集似乎不仅仅在完成这项工作。需要帮助。

  (gdb) x/50i splraise
   0xc0100d40:  mov    0x4(%esp),%edx
   0xc0100d44:  mov    %fs:0x214,%eax
   0xc0100d4a:  cmp    %edx,%eax
   0xc0100d4c:  ja     0xc0100d55
   0xc0100d4e:  mov    %edx,%fs:0x214
   0xc0100d55:  ret
   0xc0100d56:  lea    0x0(%esi),%esi
   0xc0100d59:  lea    0x0(%edi,%eiz,1),%edi
   (gdb) p spllower
   $38 = {<text variable, no debug info>} 0xc0100d60
   0xc0100d60:  mov    0x4(%esp),%ecx
   0xc0100d64:  mov    %fs:0x214,%edx
   0xc0100d6b:  cmp    %edx,%ecx
   0xc0100d6d:  push   %ebx
   0xc0100d6e:  jae,pn 0xc0100d8f
   0xc0100d71:  mov    %fs:0x210,%eax
   0xc0100d77:  test   %eax,%fs:0x244(,%ecx,4)
   0xc0100d7f:  mov    %eax,%ebx
   0xc0100d81:  jne,pn 0xc0100d91
   0xc0100d84:  cmpxchg8b %fs:0x210
   0xc0100d8c:  jne,pn 0xc0100d71
   0xc0100d8f:  pop    %ebx
   0xc0100d90:  ret
   0xc0100d91:  pop    %ebx
   0xc0100d92:  jmp    0xc0100df0
   0xc0100d97:  mov    %esi,%esi
   0xc0100d99:  lea    0x0(%edi,%eiz,1),%edi
   0xc0100da0:  mov    0x4(%esp),%ecx
   0xc0100da4:  mov    %fs:0x214,%edx
   0xc0100dab:  cmp    %edx,%ecx
   0xc0100dad:  push   %ebx
   0xc0100dae:  jae,pn 0xc0100dcf
   0xc0100db1:  mov    %fs:0x210,%eax
   0xc0100db7:  test   %eax,%fs:0x244(,%ecx,4)
   0xc0100dbf:  mov    %eax,%ebx
   0xc0100dc1:  jne,pn 0xc0100dd1
   0xc0100dc4:  cmpxchg8b %fs:0x210
   0xc0100dcc:  jne,pn 0xc0100db1
   0xc0100dcf:  pop    %ebx
   0xc0100dd0:  ret
   0xc0100dd1:  pop    %ebx
   0xc0100dd2:  jmp    0xc0100df0
   0xc0100dd7:  mov    %esi,%esi
   0xc0100dd9:  lea    0x0(%edi,%eiz,1),%edi
   0xc0100de0:  nop
   0xc0100de1:  jmp    0xc0100df0

该代码似乎正在使用辅助功能 cx8_spllower ,从地址 0xc0100da0 开始。

1 个答案:

答案 0 :(得分:2)

使用以下命令清除[E|R]FLAGS.IE CLI禁用CPU上的所有(可屏蔽的)中断。 出于多种原因,这可能是不可取的(例如,您希望允许某些,或者您不希望在VM中虚拟化CLI的开销)。

实现该目标的另一种方法是告诉中断控制器(旧的8259 PIC或Pentium APIC / IOAPIC)您不希望服务优先级低于特定级别的中断。为此,您需要与控制器进行通信,这本身可能会产生额外的开销(与真实硬件和虚拟硬件的通信速度都很慢)。

后者的一种变体是将当前中断级别/优先级保留在变量中,并允许中断进入,但仅真正服务那些其级别/优先级不低于该变量中当前中断/优先级的中断。那些未服务的设备将被标记为待处理,并且在当前级别/优先级下降到足够低时将得到全面的服务。这就是splraise()spllower()简单得多的原因。

此级别/优先级变量在代码的不同位置和版本中似乎使用不同的名称:CPL(不要与CPU的当前特权级别混淆),{{1} }(?),SPL

这是我目前对实现的有限理解。还有更多细节。

以下是我找到并用于答案的一些线索: