Board logo

标题: 深入理解 x86/x64 的中断体系(3) [打印本页]

作者: yuyang911220    时间: 2015-10-20 21:20     标题: 深入理解 x86/x64 的中断体系(3)

2.4 IDT 表的 limit 检查  在 IDT 表中查找索引 gate descriptor 时,processor 也会对 IDT 表的 limit 进行检查,这个检查的逻辑是:
  
gate_descriptor = IDTR.base + vector * 8;                  /* get gate descriptor */
if ((gate_descriptor + sizeof(DESCRIPTOR) - 1) > (IDTR.base + IDTR.limit))
  {
        /* failure: #GP exception */
}
   
  我们看看下面这个图:
  
  当我们设:
    那么 IDT 表的有效地址范围是:0x10000 - 0x1001f,也就是:IDTR.base + IDTR.limit 这表示:
    上面是这 4 个 vector 的有效范围,因此:当设 IDTR.limit = 0x1e 时,如果访问 vector 3 时(调用中断3)processor 检测到访问 IDT 越界而出错!
  因此:访问的 vector 地址在 IDTR.base 到 IDTR.base + IDTR.limit(含)之外,将会产生 #GP 异常。
  2.5 请求访问 interrupt handler 时的权限检查  访问权限的检查是 x86/x64 体系中保护措施中非常重要的一环,它控制着访问者是否有权限进行访问,在访问 interrupt handler 过程权限控制中涉及 3权限类别
    CPL 权限级别代表着访问者的权限,也就是说当前正在执行代码的权限,要理解权限控制的逻辑,你需要明白下面两点:
    在调用 interrupt handler 中并不使用 selector 来访问 gate 而是使用使用 vector 来访问 gate,因此中断权限控制中并不使用 RPL 权限类别,我们可以得知中断访问权限控制的要素:
    需同时满足上面的两个式子,在比较表达式中数字高的权限低,数字低的权限高!用 C 描述为:
  
DPLg = gate_descriptor.DPL;               /* DPL of gate */
DPLs = code_descriptor.DPL;               /* DPL of code segment */
if ((CPL <= DPLg) && (CPL >= CPLs))
  {
     /* pass */
} else {
     /* failure: #GP exception */
}
   
  2.5.1 gate 的权限设置  对于 gate 的权设置,我们应考虑 interrupt handler 调用上的两个原则:
    由这两个原则产生了 gate 权根设置的两个设计方案:
    这是现代操作系统典型的 gate 权限设置思路,绝大部分的 gate 都设置为高权限,仅有小部分允许用户访问。很明显:系统服务例程的调用入口应该设置为 3 级,以供用户调用
  下面是很典型的设计:
    系统调用在每个 OS 实现上可能是不同的,#BP 异常必定是 vector 3,因此对于 vector 3 所使用的 gate 必须使用 3 级权限。
  下面是在 windows 7 x64 操作系统上的 IDT 表的设置:
   
<bochs:2> info idt
Interrupt Descriptor Table (base=0xfffff80004fea080, limit=4095):
IDT[0x00]=64-Bit Interrupt Gate target=0x0010:fffff80003abac40, DPL=0
IDT[0x01]=64-Bit Interrupt Gate target=0x0010:fffff80003abad40, DPL=0
IDT[0x02]=64-Bit Interrupt Gate target=0x0010:fffff80003abaf00, DPL=0
  IDT[0x03]=64-Bit Interrupt Gate target=0x0010:fffff80003abb280, DPL=3
  IDT[0x04]=64-Bit Interrupt Gate target=0x0010:fffff80003abb380, DPL=3
IDT[0x05]=64-Bit Interrupt Gate target=0x0010:fffff80003abb480, DPL=0
... ...
IDT[0x29]=64-Bit Interrupt Gate target=0x0010:fffff80003bf2290, DPL=0
IDT[0x2a]=64-Bit Interrupt Gate target=0x0010:fffff80003bf22a0, DPL=0
IDT[0x2b]=64-Bit Interrupt Gate target=0x0010:fffff80003bf22b0, DPL=0
  IDT[0x2c]=64-Bit Interrupt Gate target=0x0010:fffff80003abca00, DPL=3
  IDT[0x2d]=64-Bit Interrupt Gate target=0x0010:fffff80003abcb00, DPL=3

  IDT[0x2e]=64-Bit Interrupt Gate target=0x0010:fffff80003bf22e0, DPL=0
IDT[0x2f]=64-Bit Interrupt Gate target=0x0010:fffff80003b09590, DPL=0
IDT[0x30]=64-Bit Interrupt Gate target=0x0010:fffff80003bf2300, DPL=0
      
    上面的粗体显示 interrupt gate 被设置为 3 级,在 windows 7 x64 下 vector 0x2c0x2d 被设置为系统调用接口。实际上这两个 vector 的入口虽然不同,但是代码是一样的。你可以通过 int 0x2cint 0x2d 请求系统调用。
    那么对于系统内部使用的 gate 我们应该保持与用户的隔离,绝大部分 interrupt handler 的 gate 权限都是设置为 0 级的。
    2.5.2 interrupt handler 的 code segment 权限设置    前面说过:interrupt handler 的执行权限应该至少不低于调用者的权限,意味着 interrupt handler 需要在高权限级别下运行。无论是系统提供给用户的系统服务例程还是系统内部使用的 interrupt handler 我们都应该将 interrupt handler 设置为 0 级别的运行权限(最高权限),这样才能保证 interrupt handler 能访问系统的全部资源。
    在权限检查方面,要求 DPLs 权限(interrupt handler 的执行权限)要高于或等于调用者的权限,也就是 CPL 权限,当数字上 DPLs 要小于等于 CPL(DPLs <= CPL)。
    2.6 使用 interrupt gate    使用 interrupt gate 来构造中断调用机制的,当 processor 进入 interrupt handler 执行前,processor 会将 eflags 值压入栈中保存并且会清 eflags.IF 标志位,这意味着进入中断后不允许响应 makeable 中断(可屏蔽中断)。它的逻辑 C 描述为:
          
*(--esp) = eflags;                           /* push eflags */
if (gate_descriptor.type == INTERRUPT_GATE)
          eflags.IF = 0;                       /* clear eflags.IF */
     
          interrupt handler 使用 iret 指令返回时,会将栈中 eflags 值出栈以恢复原来的 eflags 值。
          下面是 interrupt gate 的结构图:
          
          可以看到 interrupt gate 和 trap gate 的结构是完全一样的,除了以 type 来区分 gate 外,interrupt gate 的类型是:
                    32 位的 offset 值提供了 interrupt handler 的入口偏移地址,这个偏移量是基于 code segment 的 base 值,selector 域提供了目标 code segment 的 selector,用来在 GDT LDT 进行查找 code segment descriptor。这些域的使用描述为:
            
if (gate_descriptor.selector.TI == 0)
        code_descriptor = GDTR.base + gate_descriptor.selector * 8;        /* GDT */
else
        code_descriptor = LDTR.base + gate_descriptor.selector * 8;        /* LDT */

interrupt_handler = code_descriptor.base + gate_descriptor.offset;         /* interrupt handler entry */
     
            注得注意的是:在 interrupt gate 和 trap gate 中的 selector 它的 RPL 是不起作用的,这个 selector.RPL 将被忽略
            在 OS 的实现中大部分的 interrupt handler 都是使用 interrupt gate 进行构建的。在 windows 7 x64 系统上全部都使用 interrupt gate 并没有使用 trap gate




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0