x86 硬件/软件 TSS 使用情况

Posted

技术标签:

【中文标题】x86 硬件/软件 TSS 使用情况【英文标题】:x86 Hardware/Software TSS usage 【发布时间】:2021-10-26 23:51:22 【问题描述】:

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

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

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

    如果我加载一个 TSS,这个中断如何知道它应该使用这个 TSS?使用 ltr 指令将在 GDT 中获取相应的 tss 段?

    不是很相关,但是当使用硬件上下文切换和jmp到一个TSS时,它会在返回时自动跳转到上一个(没有下一个字段所以我有点迷茫)tss段吗?

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

【问题讨论】:

如果您在环 0 中运行所有内容,那么您不需要 TSS,因为不会发生环转换。但是,如果您的代码在 Ring 3(大多数人称之为用户模式)中运行,您将需要一个 TSS 以在中断时从 Ring 3 转换到 Ring 0。当发生中断时,所有内容都在 Ring 0 中时,内核(Ring 0)堆栈将用于推送中断数据。 【参考方案1】:

作为 cmets 中的 Michael Petch explained,如果中断处理程序以相同的权限执行,则不需要 TSS。

仅当中断将在当前代码的环中更高特权的环中执行(例如从环 3 到环 0 的转换)时,CPU 才会从 TSS 读取必要的 SS:SP 对。 这在第三版英特尔手册的第 6.12.1 章中有详细说明:

当处理器调用异常或中断处理程序时:

如果处理程序将在数值较低的特权级别上执行,则会发生堆栈切换。 发生堆栈切换时: -。处理程序要使用的堆栈的段选择器和堆栈指针是从当前执行任务的 TSS 中获得的。在这个新堆栈上,处理器推送堆栈段选择器并 被中断过程的堆栈指针。 [已编辑]

如果处理程序将在与被中断的过程相同的特权级别执行: 一种。处理器将 EFLAGS、CS 和 EIP 寄存器的当前状态保存在当前堆栈中(见图 6-4). [已编辑]

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


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

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


如果我加载一个 TSS,这个中断如何知道它应该使用这个 TSS?使用 ltr 指令将在 GDT 中获取相应的 tss 段?

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

所以是的,ltr 指令是操作系统控制当前活动的 TSS 的方式。


不是很相关,但是当使用硬件上下文切换和jmp到一个TSS时,它会在返回时自动跳转到上一个(没有下一个字段所以我有点迷茫)tss段吗?

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

如果任务是嵌套的(即使用callint 和中断或异常调用),CPU 将使用iret 指令读取上一个任务链接 以查找暂停的任务要恢复。

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

这是手册中的图片:

【讨论】:

感谢您的清晰解释!现在事情更清楚了,但我仍然想知道在选择要跳转到或调用到的 TSS 段时是否使用了 RPL 字段?前一个任务字段也必须“手动”设置,而且不是自动的? @Leosa99_ RPL 在调用/跳转到任务门时肯定会使用,但在直接使用任务描述符时似乎没有使用。不使用任务门内的 TSS 选择器的 RPL。英特尔的手册有更多详细信息,我不记得全部了NT 标志)来伪造一个嵌套任务。

以上是关于x86 硬件/软件 TSS 使用情况的主要内容,如果未能解决你的问题,请参考以下文章

TPM及TSS协议栈的安装

TSS学习记录

像 PTLsim 这样的 CAS 模拟器如何实现 x86 硬件的周期精确模拟?

Linux系统下x86和ARM的区别有哪些?

一文讲透!Windows内核 & x86中断机制详解

qemu能模拟全部x86指令吗