Call Gate、Interrupt Gate、Trap Gate的区别是什么?

50

我正在学习Intel保护模式。我发现调用门(Call Gate)、中断门(Interrupt Gate)和陷阱门(Trap Gate)几乎是一样的。实际上,除了调用门中有参数计数器(parameter counter)字段以及这三种门有不同类型(type)字段之外,它们在所有其他字段上都是相同的。

至于它们的功能,它们都用于将代码控制转移到某个代码段内的某个过程。

我想知道,既然这三个门都包含跨特权级调用所需的信息,为什么我们需要三种呢?难道一个不就够了吗?

感谢您的时间和回复。

更新1

一个相关的问题:何时使用中断门或陷阱门?

更新2

今天我想到了这个想法:

目的不同,门也不同,并具有不同的CPU行为细节,例如IF标志处理。


1
在我查看了其他架构,例如ARM之后,我感觉x86由于其复杂性而自我毁灭了... - smwikipedia
3个回答

69
一个门(调用、中断、任务或陷阱)用于在段之间传输执行控制。特权级检查根据目的地类型和使用的指令而异。
调用门使用CALL和JMP指令。调用门将控制从低特权级代码转移到高特权级代码。门DPL用于确定哪些特权级可以访问该门。调用门已经逐渐被SYSENTER/SYSEXIT机制取代,后者更快。
任务门用于硬件多任务支持。硬件任务切换可以自愿发生(调用/跳转到任务门描述符),也可以通过中断或设置NT标志的IRET发生。中断或陷阱门的工作方式相同。据我所知,内核通常希望在任务切换时完成额外的工作,因此不使用任务门。
中断和陷阱门与任务门一起称为中断描述符表。它们的工作方式与调用门相同,只是从一个特权级堆栈到另一个堆栈传输参数。一个区别是中断门会清除EFLAGS中的IF位,而陷阱门不会。这使它们非常适合服务硬件中断。陷阱在硬件辅助虚拟化中广泛使用。
有关更多信息,请参阅您感兴趣的处理器的英特尔架构手册。
更新
回答评论:
有许多理由区分中断和陷阱。其中一个区别是范围的不同:中断门指向内核空间(毕竟,内核管理硬件),而陷阱在用户空间中调用。中断处理程序是响应硬件事件而调用的,而陷阱是响应CPU指令而执行的。
为了更好地理解为什么中断和陷阱门会以不同的方式处理 EFLAGS,让我们举一个简单但不切实际的例子。假设我们正在为单处理器系统上的硬件事件编写中断处理程序,并且我们无法在服务第一个事件时清除 IF 位。这样,第二个事件可能在我们服务第一个事件时到达。然后,在我们执行 IH 的某个随机点上,处理器会调用我们的中断处理程序。这可能导致数据损坏、死锁或其他问题。实际上,禁用中断是确保一系列内核语句被视为关键部分的机制之一。
以上示例假定可屏蔽中断。无论如何,您都不希望忽略 NMIs。
今天它基本上是不相关的。现在几乎没有快速和慢速中断处理程序(搜索“快速和慢速处理程序”)之间的区别,中断处理程序可以嵌套执行,SMP 处理器使本地中断禁用与自旋锁耦合成为必须,等等。
现在,陷阱门确实用于服务软件中断、异常等。处理器中的页面故障或除零异常可能通过陷阱门处理。使用陷阱门控制程序执行的最简单示例是INT 3指令,它用于在调试器中实现断点。在虚拟化时,发生的情况是hypervisor在ring 0中运行,而guest kernel通常在ring 1中运行-特权代码将失败并引发一般例外故障。Witchel和Rosenblum开发了二进制翻译,其基本上是重写指令以模拟其效果。关键指令被发现并替换为陷阱。然后,当触发陷阱时,控制权被移交给VMM/hypervisor,后者负责在ring 0中仿真关键指令。
有硬件辅助虚拟化后,trap-and-emulate技术在其使用方面受到了一定的限制(因为它相当昂贵,特别是在动态环境中),但二进制翻译的实践仍广泛使用
如需更多信息,建议查看:

希望这可以帮到您!


感谢您详细的回复。您能否更详细地解释中断和陷阱门?例如,为什么中断和陷阱门对待EFLAGS [IF]不同?为什么这使它们成为处理硬件中断的理想选择?我的理解是,中断门是用于可屏蔽硬件中断,而陷阱门是用于软件中断(由代码执行异常或INT X指令引起)。此外,您能否给我提供有关如何在硬件辅助虚拟化中使用陷阱的更多参考资料?很抱歉问题这么多... - smwikipedia
谢谢你的回答。我这里有一些新问题:http://stackoverflow.com/questions/3442193/when-to-use-interrupt-gate-or-trap-gate 你能帮我解决吗?非常感谢你花费这么多时间回答我的问题。 - smwikipedia
喜欢你的回答!而且关于Linux设备驱动程序的书真的很好。 - Timothy Leung

31

架构和设计

从保护的角度来看,x86架构基于分层环,根据这个环,处理器提供的所有执行空间都被划分为四个层级保护域,每个域都有其自己分配的特权级别。这种设计假定大多数代码将在最低特权域中执行,有时需要从更高特权安全域请求服务,并将这些服务抢占到堆栈上,然后以一种方式恢复它,使整个抢占对较低特权代码不可见。

分层保护域设计规定控制不能在不同的安全域之间任意传递。

门是x86架构的一个特性,用于从低特权代码段向高特权代码段进行控制转移,反之则不行。此外,从哪个低特权片段传递控制可以是任意的,但是从哪个高特权片段传递控制必须严格指定。向低特权片段的回溯控制只允许使用IRET指令。因此,在这方面,英特尔软件开发手册指出:

低特权段中的代码模块只能通过称为门的受控受保护接口访问在更高特权段操作的模块。未经过保护门且没有足够的访问权限进行访问更高级别段的尝试会引发一个通用保护异常(#GP)。

换句话说,门是具有所需访问权限和目标地址的特权域入口点。因此所有的门都相似并用于几乎相同的目的,而所有门描述符都包含DPL字段,该字段由处理器用于控制访问权限。但请注意,当调用源是硬件时,处理器只检查门的DPL,如果调用源是软件CALLJMPINT指令,则绕过此检查。

门的类型

尽管所有的门都相似,但它们之间存在一些差异,因为最初英特尔工程师认为不同的门将用于不同的目的。

任务门

任务门只能存储在IDT和GDT中,并可以由INT指令调用。这是一种非常特殊的门类型,与其他门有很大的不同。

起初,英特尔的工程师们认为他们将通过提供基于CPU的任务切换功能来革新多任务处理。他们引入了TSS(任务状态段),用于保存任务的寄存器状态并可用于硬件任务切换。触发硬件任务切换有两种方法:使用TSS本身和使用任务门。要进行硬件任务切换,可以使用CALLJMP指令。如果我理解正确,任务门被引入的主要原因是为了能够在中断到达时触发硬件任务切换,因为无法通过JMP到TSS选择器触发硬件任务切换。
实际上,没有人使用它或者硬件上下文切换。从性能的角度来看,这个功能实际上并不是最优的,而且使用起来也不方便。例如,考虑到TSS只能存储在GDT中,并且GDT的长度不能超过8192,从硬件的角度来看我们最多只能有8k个任务。
陷阱门只能存储在IDT中,并且由INT指令调用。它可以被视为一种基本类型的门。它只是将控制权传递到更高特权级别段中指定的陷阱门描述符地址,仅此而已。陷阱门被广泛用于不同的目的,其中包括:
- 系统调用实现(例如Linux使用INT 0x80,Windows使用INT 0x2E)。 - 异常处理实现(在异常的情况下我们没有理由禁用中断)。 - 在具有APIC的机器上实现中断处理(我们可以更好地控制内核栈)。
中断门也只能存储在IDT中,并且由INT指令调用。它和陷阱门相同,但额外的中断门调用通过自动清除EFLAGS寄存器中的IF标志禁止了将来的中断接受。
中断门被广泛用于中断处理的实现,特别是在基于PIC的机器上。原因在于要控制堆栈深度。PIC没有中断源优先级功能。因此,默认情况下,PIC仅禁用已在处理器中处理的中断。但是,其他中断仍然可能在中途到达并抢占中断处理。因此,在同一时刻内内核堆栈中可能会有15个中断处理程序。结果,内核开发人员被迫要么显著增加内核堆栈大小,这导致内存惩罚,要么准备面对零星的内核堆栈溢出。中断门可以保证在同一时间内只有一个处理程序可以在内核堆栈上。
调用门可以存储在GDL和LDT中,并且由CALLJMP指令调用。与陷阱门类似,但还可以从用户模式任务堆栈传递参数到内核模式任务堆栈。传递的参数数量在调用门描述符中指定。调用门从未流行起来。原因如下:
  • 它们可以被陷阱门所取代(奥卡姆剃刀)。
  • 它们不太可移植。其他处理器没有这些特性,这意味着在移植操作系统时支持调用门作为系统调用是一种负担,因为那些调用必须被重写。
  • 由于可以在堆栈之间传递的参数数量有限,它们不太灵活。
  • 从性能角度来看,它们不太优化。

在1990年代末期,英特尔和AMD引入了用于系统调用的额外指令:SYSENTER/SYSEXIT(英特尔)和 SYSCALL/SYSRET(AMD)。与调用门相比,新指令提供了性能优势,并得到了广泛应用。

总结

我不同意Michael Foukarakis的观点。很抱歉,除了影响IF标志位外,中断和陷阱之间没有任何区别。

  • 从理论上讲,每种类型的门都可以作为接口,指向具有任何特权级别的段。实际上,在现代操作系统中,只有中断和陷阱门被用于IDT的系统调用、中断和异常处理,并且由于这个原因,它们都作为内核入口点。

  • 任何类型的门(包括中断、陷阱和任务)都可以通过使用INT指令在软件中调用。唯一能够禁止用户模式代码访问特定门的特性是DPL。例如,当操作系统构建IDT时,无论具体门的类型如何,内核都会将用于硬件事件处理的门的DPL设置为0,并根据此将仅允许来自内核空间(运行在最高特权域的空间)的访问该门,但当设置系统调用的门时,它将DPL设置为3以允许从任何代码访问该门。结果,用户模式任务可以使用DPL = 3的门进行系统调用,但是如果尝试调用键盘中断处理程序,则会捕获常规保护故障。

  • IDT中的任何类型的门都可以被硬件调用。人们只在想要实现某些同步的情况下使用中断门来处理这些硬件事件。例如,确保内核栈溢出是不可能的。例如,我有在基于APIC的系统上使用陷阱门处理硬件中断的成功经验。

  • 同样地,可以通过软件调用IDT中任何类型的门。使用陷阱门进行系统调用和异常的原因很简单。没有理由禁用中断。禁用中断是一件坏事,因为它会增加中断处理延迟并增加中断丢失的概率。因此,没有任何人会在手头没有严重原因的情况下禁用它们。

  • 中断处理程序通常采用严格可重入的方式编写。这样,中断处理程序通常不共享数据并可以透明地抢占彼此。即使我们需要互斥地访问中断处理程序中的数据,我们也只能使用cli和sti指令来保护对共享数据的访问。没有任何理由将整个中断处理程序视为关键部分。除了希望防止基于PIC系统的内核堆栈溢出之外,没有任何理由使用中断门。

陷阱门是内核接口的默认解决方案。如果有一些严重的原因,可以使用中断门代替陷阱门。


2
我正在尽力清理这个问题,因为你在这里提供了一些真正有价值的东西,但由于语法和拼写错误而被忽视。请继续关注。这个答案是顶级的。 - Evan Carroll

9

中断门是特殊的,因为IF标志自动清除。调用门是特殊的,因为它不通过中断向量被激活。任务门是特殊的,因为它会自动保存处理器状态。有四种不同的行为,为它们取了四个名称是很方便的。


谢谢您的回复。陷阱门怎么样? - smwikipedia
好的,它使用向量,不重置IF,也不保存CPU状态。与其他三个不同。 - Hans Passant
CPU是否检查中断/陷阱门的TYPE字段以决定是否重置IF位?因为Type字段是这两个门之间唯一的区别。 - smwikipedia
是的,类型字段决定了行为。 - Hans Passant
谢谢Hans。我们如何知道将向量号分配给中断门或陷阱门?标准是什么? - smwikipedia
我看到你在那个话题上发布了另一个问题。在这里回答似乎相当不合适。 - Hans Passant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接