调用门、中断门、陷阱门的区别?

发布于 2024-09-13 17:50:49 字数 472 浏览 2 评论 0原文

我正在研究英特尔保护模式。我发现Call Gate、Interrupt Gate、Trap Gate几乎是一样的。事实上,除了Call Gate有参数计数器字段以及这3个门有不同的类型字段外,它们在所有其他字段中都是相同的。

从功能上来说,它们都是用于将代码控制权转移到某个代码段内的某个过程中。

我想知道,因为这 3 个门都包含跨特权边界调用所需的信息。为什么我们需要 3 种? 1 还不够好吗?

感谢您的时间和回复。

更新1

相关问题:何时使用中断门或陷阱门?< /a>

更新 2

今天我想到了这个想法:

不同的目的,不同的门,以及执行不同的 CPU 行为细节。比如IF标志的处理。

I am studying Intel Protected Mode. I found that Call Gate, Interrupt Gate, Trap Gate are almost the same. In fact, besides that Call Gate has the fields for parameter counter, and that these 3 gates have different type fields, they are identical in all other fields.

As to their functions, they are all used to transfer code control into some procedure within some code segment.

I am wondering, since these 3 gates all contain the information needed for the call across privilege boundaries. Why do we need 3 kinds of them? Isn't 1 just good enough?

Thanks for your time and response.

Update 1

A related question: When to use Interrupt Gate or Trap Gate?

Update 2

Today I came up with this thought:

Different purpose, different gates, and with different CPU behavior details carried out. Such as IF flag handling.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

会傲 2024-09-20 17:50:49

门(调用、中断、任务或陷阱)用于跨段转移执行控制。根据目的地类型和所使用的指令,权限级别检查的执行方式有所不同。

调用门使用 CALL 和 JMP 指令。调用门将控制权从较低特权代码转移到较高特权代码。门 DPL 用于确定哪些特权级别可以访问该门。调用门正在(或者可能已经)逐渐被放弃,取而代之的是速度更快的 SYSENTER/SYSEXIT 机制。

任务门用于硬件多任务支持。硬件任务切换可以自动发生(对任务门描述符的 CALL/JMP),也可以在设置 NT 标志时通过中断或 IRET 发生。它的工作方式与中断门或陷阱门相同。据我所知,没有使用任务门,因为内核通常希望在任务切换时完成额外的工作。

中断&陷阱门与任务门一起称为中断描述符表。它们的工作方式与调用门相同,除了从一个特权堆栈到另一个特权堆栈的参数传输之外。一个区别是中断门会清除 EFLAGS 中的 IF 位,而陷阱门则不会。这使它们成为服务硬件中断的理想选择。陷阱广泛应用于硬件辅助虚拟化中。

有关更多信息,请参阅有关您感兴趣的处理器的英特尔架构手册。

更新

回答评论:

区分中断和陷阱的原因有很多。一是范围的差异:中断门指向内核空间(毕竟是内核管理硬件),而陷阱在用户空间中调用。调用中断处理程序以响应硬件事件,而执行陷阱以响应 CPU 指令。

为了更好地理解为什么中断门和陷阱门以不同的方式对待 EFLAGS,请举一个简单(但不切实际)的示例,考虑一下如果我们在单处理器系统上为硬件事件编写中断处理程序并且我们无法清除 IF 位,会发生什么情况正在服务一个。当我们忙于服务第一个中断时,第二个中断可能会到来。然后,在 IH 执行期间,处理器将在某个随机点调用我们的中断处理程序。这可能会导致数据损坏、死锁或其他不良情况。实际上,中断禁用是确保一系列内核语句被视为关键部分的机制之一。

不过,上面的示例假设是可屏蔽中断。无论如何,您都不想忽略 NMI。

今天这也基本上无关紧要。如今,快中断处理程序和慢中断处理程序之间几乎没有区别(搜索对于“快速和慢速处理程序”),中断处理程序可以以嵌套方式执行,SMP 处理器强制将本地中断禁用与自旋锁结合起来,等等。

现在,陷阱门确实用于服务软件中断、异常等。处理器中的页面错误或除零异常可能是通过陷阱门处理的。使用陷阱门控制程序执行的最简单示例是 INT 3 指令,该指令用于在调试器中实现断点。在进行虚拟化时,会发生的情况是虚拟机管理程序在环 0 中运行,而来宾内核通常在环 1 中运行 - 特权代码将因一般异常错误而失败。 Witchel 和 Rosenblum 开发了二进制翻译,这基本上是重写指令来模拟其效果。关键指令被发现并被陷阱取代。然后,当陷阱执行时,控制权交给 VMM/管理程序,它负责模拟环 0 中的关键指令。

通过硬件辅助虚拟化,陷阱和模拟技术的使用受到一定限制(因为它是相当昂贵,尤其是在动态时),但二进制翻译的实践仍然广泛使用。

有关详细信息,我建议您查看:

  • Linux 设备驱动程序,第三版(可在线获取)
  • 对于二进制翻译,QEMU 是一个很好的开始。
  • 关于陷阱和仿真,请查看软件/硬件技术之间的比较

希望这有帮助!

A gate (call, interrupt, task or trap) is used to transfer control of execution across segments. Privilege level checking is done differently depending on the type of destination and instruction used.

A call gate uses the CALL and JMP instructions. Call gates transfer control from lower privilege code to higher privilege code. The gate DPL is used to determine what privilege levels have access to the gate. Call gates are (or have been, probably) gradually abandoned in favour of the SYSENTER/SYSEXIT mechanism, which is faster.

Task gates are used for hardware multitasking support. A hardware task switch can occur voluntarily (CALL/JMP to a task gate descriptor), or through an interrupt or an IRET when the NT flag is set. It works the same way with interrupt or trap gates. Task gates are not used, to the best of my knowledge, as kernels usually want extra work done when task switching.

Interrupt & trap gates, together with task gates, are known as the Interrupt Descriptor Table. They work the same as call gates, except the transfer of parameters, from one privilege stack to another. One difference is that interrupt gates clear the IF bit in EFLAGS, while trap gates do not. This makes them ideal for serving hardware interrupts. Traps are widely used in hardware-assisted virtualization.

For more information, see the Intel Architecture Manuals on the processors that interest you.

Update

To answer the comment:

There are many reasons to distinguish interrupts from traps. One is the difference in scope: interrupt gates point to kernel space (after all, it's the kernel who manages the hardware) while traps are called in userspace. Interrupt handlers are called in response to hardware events, while traps are executed in response to an CPU instruction.

For a simple (but impractical) example to better understand why interrupt and trap gates treat EFLAGS differently, consider what would happen in case we were writing an interrupt handler for hardware events on a uniprocessor system and we couldn't clear the IF bit while we were serving one. It would be possible for a second interrupt to arrive while we were busy serving the first. Then our interrupt handler would be called by the processor at some random point during our IH execution. This could lead to data corruption, deadlocking, or other bad magic. Practically, interrupt disabling is one of the mechanisms to ensure that a series of kernel statements is treated like a critical section.

The above example is assuming maskable interrupts, though. You wouldn't want to ignore NMIs, anyway.

It's largely irrelevant today, too. Today there's practically no distinction between fast and slow interrupt handlers (search for "Fast and Slow Handlers"), interrupt handlers can execute in nested fashion, SMP processors make it mandatory to couple local interrupt disabling with spin locks, and so forth.

Now, trap gates are indeed used to service software interrupts, exceptions, etc. A page fault or division by zero exception in your processor is probably handled through a trap gate. The simplest example of using trap gates to control program execution is the INT 3 instruction, which is used to implement breakpoints in debuggers. When doing virtualization, what happens is that the hypervisor runs in ring 0, and the guest kernel usually in ring 1 - where privileged code would fail with general exception fault. Witchel and Rosenblum developed binary translation, which is basically rewriting instructions to simulate their effects. Critical instructions are discovered and replaced with traps. Then when the trap executes, control is yielded to the VMM/hypervisor, which is responsible for emulating the critical instructions in ring 0.

With hardware-assisted virtualization, the trap-and-emulate technique has been somewhat limited in its use (since it's quite expensive, especially when it's dynamic) but the practice of binary translation is still widely used.

For more information, I'd suggest you check out:

  • Linux Device Drivers, Third Edition (available online)
  • For binary translation, QEMU is an excellent start.
  • Regarding trap-and-emulate, check out a comparison between software/hardware techniques.

Hope this helps!

幸福丶如此 2024-09-20 17:50:49

架构与设计

从保护的角度来看,x86架构是基于分层环的,根据分层环,处理器交付的所有执行空间被分为四个分层保护域,每个域都分配有自己的权限级别。此设计假设大多数情况下代码将在特权最小的域中执行,有时将请求来自特权较高的安全域的服务,并且该服务将抢占堆栈中特权较低的活动,然后以以下方式恢复它:对于特权较低的代码来说,整个抢占将是不可见的。

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

门是 x86 架构的一项功能,用于将控制从特权较低的代码段转移到特权较高的代码段,但反之则不然。此外,特权较低的段中控制权传递的点可以是任意的,但特权较高的段中控制权传递的点是严格指定的。仅允许通过 IRET 指令将向后控制传递到特权较低的段。对此,英特尔软件开发人员手册声称:

较低权限段中的代码模块只能通过称为门的严格控制和保护的接口来访问在较高权限段中运行的模块。尝试在不通过保护门且没有足够访问权限的情况下访问更高权限的段会导致生成一般保护异常 (#GP)。

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

门的类型

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

任务门

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

最初,英特尔工程师认为他们将通过提供基于 CPU 的任务切换功能来彻底改变多任务处理。他们引入了 TSS(任务状态段),它保存任务的寄存器状态,可用于硬件任务切换。触发硬件任务切换有两种方式:使用TSS本身和使用Task Gate。要进行硬件任务切换,您可以使用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 指令调用。与陷阱门类似,但此外还可以将多个参数从用户模式任务堆栈传递到内核模式任务堆栈。传递的参数数量在调用门描述符中指定。

呼叫门从来不受欢迎。原因如下:

  • 它们可以被陷阱门(奥卡姆剃刀)取代。
  • 它们不太便携。其他处理器没有这样的功能,这意味着在移植操作系统时,对系统调用的调用门的支持是一种负担,因为必须重写这些调用。
  • 它们不太灵活,因为可以在堆栈之间传递的参数数量是有限的。
  • 从性能的角度来看,它们并不是最佳的。

20 世纪 90 年代末,Intel 和 AMD 引入了额外的系统调用指令:SYSENTER/SYSEXIT (Intel) 和 SYSCALL/SYSRET< /代码>(AMD)。与调用门相比,新指令提供了性能优势并已得到采用。

总结

我不同意迈克尔·福卡拉基斯的观点。抱歉,除了影响 IF 标志之外,中断和陷阱之间没有任何区别。

  • 理论上,每种类型的门都可以作为指向具有任何权限级别的段的接口。实际上,在现代操作系统中仅使用中断门和陷阱门,它们在 IDT 中用于系统调用、中断和异常处理,因此它们都充当内核入口点。

    理论上

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

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

  • 类似地,IDT中任何类型的门都可以在软件中调用。使用陷阱门进行系统调用和异常的原因很简单。没有任何理由禁用中断。中断禁用是一件坏事,因为它会增加中断处理延迟并增加中断丢失的可能性。因此,没有任何严重的原因,没有人不会禁用它们。

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

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

Architecture and Design

From the point of view of protection, the x86 architecture is based on hierarchical rings, according to which all execution space delivered by processor is divided into four hierarchical protection domains, each of which have its own level of privileges assigned. This design assumes that most of the time code will be executed in the least privileged domain and sometimes services from the more privileged security domain will be requested and this services will preempt the less privileged activities onto the stack and then restore it in such a way that whole preemption will be invisible for the less privileged code.

The design of hierarchical protection domains state that the control can't be passed arbitrary between different security domains.

A gate is a feature of x86 architecture for control transfer from less privileged code segments to more privileged ones, but not vice versa. Furthermore, the point in the less privileged segment from where control will be passed can be arbitrary, but point in the more privileged segment to where control will be passed is strictly specified. Backward control passing to the less privileged segment is allowed only by means of IRET instruction. In this regards Intel Software developer manual claims:

Code modules in lower privilege segments can only access modules operating at higher privilege segments by means of a tightly controlled and protected interface called a gate. Attempts to access higher privilege segments without going through a protection gate and without having sufficient access rights causes a general-protection exception (#GP) to be generated.

In other words, a gate is a privileged domain entry point with required access rights and a target address. In that way all gates are similar and used for almost same purposes, and all gate descriptors contain DPL field, that used by processor to control access rights. But note, the processor checks the DPL of the gate only if the source of the call was a software CALL, JMP, or INT instruction, and bypasses this check when the source of the call is a hardware.

Types of Gates

Despite the fact that all gates are similar, they have some differences because originally Intel engineers thought that different gates would be used for different purposes.

Task Gate

A Task Gate can be stored only in IDT and GDT and called by an INT instruction. It is very special type of gate that differs significantly from the others.

Initially, Intel engineers thought that they would revolutionize multitasking by providing CPU based feature for task switching. They introduced TSS (Task State Segment) that hold registers state of the task and can be used for hardware task switching. There are two ways for triggering hardware task switching: by using TSS itself and by using Task Gate. To make hardware task switch you can use the CALL or JMP instructions. If I correctly understand, the main reason for the task gate introduction was to have the ability to trigger hardware task switches in reply to the interrupt arrival, because a hardware task switch can't be triggered by a JMP to the TSS selector.

In reality, no one uses it nor the hardware context switching. In practice, this feature isn't optimal from the performance point of view and it isn't convenient to use. For example, taking into the account that TSS can be stored only in GDT and length of GDT can't be more then 8192, we can't have more then 8k tasks from the hardware point of view.

Trap Gate

A Trap Gate can be stored only in IDT and called by an INT instruction. It can be considered as a basic type of gate. It just passes control to the particular address specified in the trap gate descriptor in the more privileged segment and nothing more.
Trap gates actively used for different purposes, that may include:

  • system call implementation (for example Linux use INT 0x80 and Windows use INT 0x2E for this purposes)
  • exception handling implementation (we haven't any reason to disable interrupts in the case of exception).
  • interrupt handling implementation on machines with APIC (we can control kernel stack better).

Interrupt Gate

An Interrupt Gate can be stored only in IDT and called by an INT instruction. It is the same as trap gate, but in addition interrupt gate call additionally prohibits future interrupt acceptance by automatic clearing of the IF flag in the EFLAGS register.

Interrupt gates used actively for interrupt handling implementation, especially on PIC based machines. The reason is a requirement to control stack depth. PIC doesn't have the interrupt sources priorities feature. Due to this by default, PIC disable only the interrupt that already on handling in processor. But another interrupts still can arrive in the middle and preempt the interrupt handling. So there is can be 15 interrupt handlers on the kernel stack in the same moment. As result kernel developers forced either to increase kernel stack size significantly that leads to the memory penalty or be ready to faced with sporadic kernel stack overflow. Interrupt Gate can provide guarantee that only one handler can be on the kernel stack in the same time.

Call Gate

A Call Gate can be stored in GDL and LDT and called by CALL and JMP instructions. Similar to trap gate, but in addition can pass number of parameters from the user mode task stack to kernel mode task stack. Number of parameters passed is specified in the call gate descriptor.

Call gates were never popular. There are few reasons for that:

  • They can be replaced by trap gates (Occam's Razor).
  • They not portable a lot. Other processors have no such features which means that support of call gates for system calls is a burden when porting the operating system as those calls must be rewriten.
  • They're not too flexible, due to the fact that amount of the parameters that can be passed between stacks is limited.
  • They're not optimal from the performance point of view.

At the end of 1990s Intel and AMD introduced additional instructions for system calls: SYSENTER/SYSEXIT (Intel) and SYSCALL/SYSRET (AMD). In contrast to the call gates, the new instructions provide a performance benefits and have found adoption.

Summary

I disagree with Michael Foukarakis. Sorry, but there are no any differences between interrupts and traps except affecting IF flag.

  • In theory, each type of gate can serve as interface pointing to a segment with any level of privileges. On practice, in modern operating system in use only interrupt and trap gates, that is used in IDT for system calls, interrupts and exception handling and due to this all they serve as kernel entry point.

  • Any type of gate (including interrupt, trap and task) can be invoked in software by using an INT instruction. The only feature that can prohibit user mode code access to particular gate is DPL. For example, when operating system builds IDT, regardless of the types of the particular gates, kernel setup DPL of the gates that will be used for hardware event handling to 0 and according to this access to this gates will be allowed only from the kernel space (that runs at most privileged domain), but when it setup gate for the system call, it set DPL to 3 to allow access to that gate from any code. In result, user mode task is able to make system call using gate with DPL = 3, but will catch General Protection Fault on attempt to call keyboard interrupt handler, for example.

  • Any type of gate in IDT can be invoked by hardware. People use interrupt gates for this hardware events handling only in cases when they want to achive some synchronization. For example to be sure that kernel stack overflow is impossible. For example, I have successfull experience of trap gates usage for hardware interrupt handling on the APIC based system.

  • Similar way, gate of any type in IDT can be called in software. The reason for the using trap gates for system call and exceptions is simple. No any reasons to disable interrupts. Interrupt disabling is a bad thing, because it increases interrupt handling latencies and increase probability of interrupt lost. Due to this no one won't disable them without any serious reason on the hands.

  • Interrupt handler usually written in strict reentrant style. In this way interrupt handlers usually share no data and can transparently preempt each other. Even when we need to mutually exclude concurrent access to the data in interrupt handler we can protect only the access to the shared data by using cli and sti instructions. No any reason to consider an whole interrupt handler as a critical section. No any reason to use interrupt gates, except desire to prevent possible kernel stack overflow on the PIC based systems.

The trap gates is a default solution for kernel interfacing. Interrupt gate can be used instead of trap gate if there is some serious reason for that.

挥剑断情 2024-09-20 17:50:49

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

An Interrupt gate is special because the IF flag is automatically cleared. A Call gate is special because it doesn't get activated through an interrupt vector. A task gate is special because it automatically saves the processor state. Four distinct behaviors, having four names for them is convenient.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文