interrupt 与 trap gate 格式是一样的,只是 descriptor type 不一样而已。与 x86 的 interrupt / trap gate 的所不同的是:base 扩展为 64 位、额外增加了 IST 域。
前面提过,由于 interrupt / trap gate 只能放在 IDT 表中,不存在 64/32 位代码共存的现象,所以,interrupt / trap gate 的高半部分的 type 域不需为 0000,而保留未用。
6.1.6.1、 interrupt gate 与 trap gate 的细微区别
interrupt 与 trap 是在格式上是完全一致,区别在于:当响应 interrupt gate 时,processor 将 Rflags.IF 清为 0,将中断标志清为 0,表示在 interrupt 例程执行完毕之前是不能响应其它的中断(可屏敝中断)。
当响应 trap gate 时,processor 不会对 Rflags.IF 标志进行修改。表示在执行 trap 例程时,可以响应其它的中断。
6.1.6.2、 IST(Intrrupt Stack Table)的使用
新增的 IST 域共 3 位,可表示 1 ~ 7 个 ID 值,代表 IST1 ~ IST7。当 IST = 0 时,表示无 IST,或者不使用 IST 功能。
IST1 ~ IST7 是索引 ID 值,在 long mode 下的 64 位 TSS segment 的 IST1 ~ IST7 中进行索引,前面已经提过在 TSS segment 中新增了 IST ~ IST7 共 7 个域,每个域为 64 位值,每个 64 位值是 stack pointer (RSP)。
假如在 interrupt/trap gate descriptor 中的 IST 设为 2,那么当响应这个 interrupt/trap 例程时,processor 据此在 TSS 中索引到 IST2,将 TSS 的 IST2 加载到 rsp 中,从而使用这个特定的 stack pointer 。
但是,若发生了权限的改变,即发生了 stack 的切换,最终仍是从相应权限的 stack pointer 加载 rsp 值,如:目标 interrupt 例程是 0 级的代码,而调用者为 3 级代码。这时发生 stack 的切换,processor 那么将从 RSP0 中加载 rsp。
IST 的价值是为 interrupt / trap 例程提供一个特定的 stack 环境。这是在未发生 stack 切换的前提下。IST 为 0 则表示不使用特定的 stack 环境。
6.1.6.3、 interrupt / trap gate 调用流程
long mode 下的 interrupt / trap gate 与 32 位下的调用流程有很大差别:
1、在 x86 下 32 位的 interrpt / trap gate 的 base(offset) 并不是真正的 interrupt / trap 例程的执行入口,执行入口首需经 interrupt/trap gate 的 selector 域得出目标 code segment 的 descriptor,然后,目标 code segment descriptor 的 base 值加上 interrupt / trap gate 的提供 offset 值,最终才形成真正的执行入口。
当然,现在绝大部分的 OS 已经在 code segment descriptor 的 base 设为 0,实际上等于 interrupt / trap gate 的 offset 就是例程的执行入口。
2、在 long mode 下的 intterupt / trap gate 的 base(offset)提供的是真正的例程执行入口地址。而 interrupt / trap gate 的 selector 仅仅只是起了权限检查的作用。当过通了权限检查后,直接将 offset 加载到 rip 进行执行。