码迷,mamicode.com
首页 > 其他好文 > 详细

[转载]long mode 模式下的中断服务例程

时间:2015-01-29 18:59:28      阅读:287      评论:0      收藏:0      [点我收藏+]

标签:

在 long mode 下,gate 是 16 字节的,并取消了对 task gate 的支持。即 IDT 的 entry 是 16 字节的,所以:gate = IDTR.base + vector * 16。

  在 long mode 下,code segment descriptor 的 L、D、C 以及 DPL 有效,其它域无效。由于 base 强制为 0,中断服务例程的入口地址就是 gate.offset,这个 offset 是 64 位值。code segment descriptor 的 L = 1 && D = 0,代表 code segment 是 64 位代码。

1、索引 gate 和 code segment descriptor

gate = IDTR.base + vector * 16;
temp_descriptor = get_descriptor(gate.selector, GDT /* LDT */);

同样,以 gate.selector 可以找到 code segment descriptor。

2、gate descriptor 和 code segment descriptor 的检查
  processor 将对 gate 和 code segment descriptor 进行检查

if (gate.type == INTERRUPT_GATE || gate.type == TRAP_GATE) {
} else {   /* #GP 异常 */ }  
if (IS_CANONICAL(gate.offset)) {                /* is canonical-address ? */
} else {   /* #GP */ }
if (temp_descriptor.L == 1 && temp_descriptor.D == 0) {            /* 64 bit */
} else {   /* #GP 异常 */ }

  processor 对 gate 额外检查 offset 是否是 canonical-address 地址形式。processor 还将对 code segment descriptor 的 L 和 D 属性进行检查,是否为 64 位代码。

3、权限 check
  DPLg 是 gate.DPL,DPLs 是 code segment descripotr.DPL

if (CPL <= DPLg && D >= DPLs) {   /* 通过,允许访问 */ } else {   /* 失败, #GP 异常 */ }

4、stack 切换      在 long mode 下的 interrupt/trap gate 增加了 IST 域,代表 1 ~ 7 stack pointer ID 值。允许在 interrupt/trap 提供自定义的 stack pointer,分别为:IST1 ~ IST7。

old_SS = SS; old_RSP = RSP;
if (gate.IST) {   SS = NULL;   RSP = TSS.IST[gate.IST].RSP;         /* Intrrupt Stack Table */
} else {
  SS = NULL:   RSP = TSS.stack[temp_descriptor.DPL].RSP;       /* stack pointer */ }
RSP |= 0xFFFFFFFF_FFFFFFF0;                /* 调整 stack 为 16 字节对齐 */
push64(old_SS); push64(old_RSP);
push64(RFlags);
push64(CS); push64(RIP);
if (ERROR_CODE) {   push64(error_code); }

(1)如果,interrupt/trap gate 的 IST 不为 0 无论是否有权限的改变,都将发生 stack 切换,以便使用 gate 提供的 IST 指针,若 gate.IST 为 0 的话,将沿有以前的的 stack 切换模式:在权限改变时发生 stack 切换。
(2)long mode 下的 stack 以 16 字节对齐,processor 额外将 RSP 调整为 16 字节对齐。
(3)SS 将被加载为 NULL selector,即:0x0000(selector),在 long mode 下的 stack 切换中 SS 被加载为 NULL-selector 是不会产生 #GP 异常的。
(4)旧的 SS & RSP、Eflags、CS & RIP 将被入栈,SS、CS 在 8 字节边界上,多余补 0 。Rflags 的高 32 位补 0 入栈。
(5)同样若是 exception 例程则入栈 error code
---------------------------------------------------------------------------------   在 long mode 下的 TSS segment 是 64 位的,其中有 6 个 RSP 指针域,构成一个 Interrupt Stack Table 表,分别为:IST1 ~ IST7,这 6 个 RSP 由 interrupt / trap gate descriptor 中的 IST 域来索引获取。   gate 中的 IST 域值为 001 ~ 111,相应地指出在 TSS 中的 IST 值。当 gate.IST 为 0 时,表示在 gate 中不提供对 IST 的索引,还是按原来的获取 stack pointer 方式。

5、Rflags 寄存器的处理

Rflags.NT = 0; Rflags.RF = 0; Rflags.TF = 0;
if (gate == INTERRUPT_GATE) {   Rflags.IF = 0; } else if (gate == TRAP_GATE) {
}

同样,processor 需将 NT、TF、RF 清为 0,在 interuupt gate 下 IF 清 0, trap-gate 下不修改 IF 标志。long mode 下不支持 virtual-8086 mode,对 VM 标志不修改。

6、加载 code segment descriptor
  和 x86 下一样,code segment selector 和 descriptor 被加载到 CS 中,但是仅 CS.L、CS.D、CS.P、CS.C 和 CS.DPL 有效,其它域无效,CS.base 被强制为 0,CS.limit 被强制为 FFFFFFFF_FFFFFFFF   CS.RPL 被更新为 code segment descriptor 的 DPL,即为当前的 CPL。  
7、执行中断服务例程      由于 CS.base 被强制为 0,因此 gate.offset 就是实际的中断服务例程入口地址。
  RIP = gate.offset 然后执行 CS:RIP 处理的中断服务例程。

8、中断服务例程的返回
  若返回到 64 bit 模式时,processor 处理将和 x86 的情形一样。但是在 64 bit 的中断服务例程里需使用 iretq 指令。
情景提示:

  由于 iret 指令在 64 bit 模式下 default operand-size 是 32 位的,这不同于 ret 指令。ret 指令的 default operand-size 是 64 位。所以,中断返回时需使用 iretq 指令,即:使用指令前缀 REX.W(48) 将 iret 调整为 iretq

7.1.3.7.1、 compatibility 模式与 64 bit 模式之间的切换
  由于 long mode 下有 compatiblity 与 64 bit 两种子模式,那么在 x64 版本的 64 位 OS 里就有可能存在 compatibility 与 64 bit 模式之间的切换情况发生。   64 位 OS 核心运行在 64 bit 模式下,当系统加载的是原 x86 下的 32 位用户程序,processor 将从 64 bit 切换到 compatiblity 模式。32 位软件返回 OS 时,从 compatibility 模式切换回 64 bit 模式。

  当原 x86 程序中使用 int 陷入系统服务例程时,processor 从 compatibility 模式切换到 64 bit 模式,从 3 级切换到 0 级代码。

[转载]long mode 模式下的中断服务例程

标签:

原文地址:http://www.cnblogs.com/Acg-Check/p/4260505.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!