x86 Hardware/Software TSS 使用

x86 Hardware/Software TSS usage

我有一个带有时钟中断的简单工作(32 位保护模式)内核。我可以看到这个中断正在工作,因为它会打印 « clock » 很多时间。我还可以看到此中断将控制权交还给内核,因为它在几次时钟中断后在屏幕上打印了«内核已停止»,就像它应该的那样。中断与内核位于同一代码段。

我没有设置任何 TSS,但它正在运行。我可以在这篇文章 (https://web.archive.org/web/20160326062442/http://jamesmolloy.co.uk/tutorial_html/10.-User%20Mode.html) 上读到,当发生中断时,cpu 将查看选定的 TSS 段以更新寄存器。

  1. 没有这个TSS怎么行?是不是因为中断发生时CPU还是会自动push EIP,CS,EFLAGS,EPS,SS并在iret上恢复?

  2. 如果我加载单个 TSS,这个中断如何知道它应该使用这个 TSS?使用 ltr 指令将采用 GDT 内相应的 tss 段?

  3. 关系不大,但是当使用硬件上下文切换和jmp到一个TSS时,会自动跳转到上一个(没有下一个字段所以我有点迷路)tss段时return ?

这些问题我无法从我的学校课程中得到明确的答案,无论是 osdev 还是这个论坛。

如评论中的 所述,如果中断处理程序以相同权限执行,则不需要 TSS。

CPU 仅当中断将在更高特权环 w.r.t 当前代码的环(例如,a从第 3 环过渡到第 0 环)。
这在 3rd Intel 手册的第 6.12.1 章中有详细说明:

When the processor performs a call to the exception- or interrupt-handler procedure:

  • If the handler procedure is going to be executed at a numerically lower privilege level, a stack switch occurs. When the stack switch occurs:
    -. The segment selector and stack pointer for the stack to be used by the handler are obtained from the TSS for the currently executing task. On this new stack, the processor pushes the stack segment selector and stack pointer of the interrupted procedure.
    [redacted]

  • If the handler procedure is going to be executed at the same privilege level as the interrupted procedure: a. The processor saves the current state of the EFLAGS, CS, and EIP registers on the current stack (see Figure 6-4).
    [redacted]

值得注意的是,在 64 位模式下不再支持任务切换机制。
我们不能 calljmp 或使用任务门。
然而,令人困惑的是,TSS 仍然在使用并且是强制性的。这个结构现在被主流 OSes 在实践中使用:作为一个全局(阅读:每个任务都相同,至少在理论上)缓冲区,用于存储堆栈切换和其他信息。
另外值得注意的是,在 64 位模式下,新的 IST 机制用于任务切换(请参阅 3rd Intel 手册的 6.14.5 节)。


How can it work if I don’t have this TSS ? Is it because when interrupts occurs the CPU will still automatically push EIP, CS, EFLAGS, EPS, SS and restore them on iret ?

当没有权限级别更改时,CPU 将不会使用 TSS。要了解推送的内容和顺序,请参阅下面这张取自英特尔手册第 3 卷的图片:


If I load a single TSS, how this interrupt will know that it should use this TSS ? With ltr instruction that will take the according tss segment inside the GDT?

当中断发生并且 CPU 意识到将要发生特权更改时,它将读取 tr 寄存器以获取当前 TSS。
由于加载 tr 是一项特权操作,因此 OS 控制着将使用什么 TSS。
事实上,如果 OS 想要使用两个不同的 TSS,AB,用于两个不同的程序 Pa Pb,每次要执行其中一个程序时,它会重新加载tr

所以是的,ltr 指令是 OS 控制当前激活的 TSS 的方式。


Not really related, but when using hardware context switching and jmp to one TSS, will it automatically jump to the previous (no next field so I’m a little bit lost) tss segment automatically when return ?

如果支持任务切换,可以通过以下方式调用:jmpcallint、中断或异常。
除了 jmp 之外的所有这些方法都会 link 当前任务(被切换的那个)到新任务(被切换的那个)。
这是通过 TSS 中的 Previous Task Link 字段实现的,新的 TSS 会将此字段设置为旧的 TSS 选择器。
据说新任务是 nested.
CPU 还将使用 NT(嵌套任务)标志来跟踪当前任务是否嵌套。

如果任务是嵌套的(即用 callint 和中断或异常调用),使用 iret 指令 CPU 将读取Previous Task Link 找到暂停的任务以恢复。

请注意,即使任务切换是使用 call 完成的(通常与 ret/retf 配对),也只能使用 iret

这是手册中的图片: