是否有关于如何布置全局描述符表条目的约定?

Posted

技术标签:

【中文标题】是否有关于如何布置全局描述符表条目的约定?【英文标题】:Is there a convention for how Global Descriptor Table entries should be laid out? 【发布时间】:2021-10-02 20:13:17 【问题描述】:

操作系统是否有约定的约定来指定每个表索引应描述的内容?例如,在 Windows 系统上(如 here 所述),条目 4 描述 32 位用户模式代码 (RPL = 3),条目 6 描述 64 位用户模式代码。这是一个约定吗?其他条目呢?

【问题讨论】:

注意对我的回答的修改:布伦丹指出了我错过的一些事情。 【参考方案1】:

x86-64 syscall/sysret 和 32 位 sysenter/sysexit,显然确实关心您的 GDT 条目的顺序:内核 CS、内核数据、用户 CS,按此顺序的用户数据。 (感谢@Brendan 提供的详细信息。)或者至少,syscall 将固定值加载到 CS 和 SS 内部状态中:

SYSCALL 使用来自 IA32_STAR MSR 的位 47:32 的值加载 CS 和 SS 选择器。但是,CS 和 SS 描述符缓存不会从这些选择器引用的描述符(在 GDT 或 LDT 中)加载。相反,描述符缓存加载固定值。有关详细信息,请参阅操作部分。操作系统软件有责任确保这些选择器值引用的描述符(在 GDT 或 LDT 中)对应于加载到描述符缓存中的固定值; SYSCALL 指令不能确保这种对应关系。

除此之外,硬件不在乎;如果您只使用像 int 0x80 这样的遗留系统调用机制,那么任何对您有意义的模式都可以。 AFAIK,跨操作系统没有标准约定,但这不是我看过的东西。


这些条目可能是在内核设置它们时通过缓存获取的(例如在上下文切换时),因此将一起使用的条目放在同一个 64 字节缓存行中可能会有一个微小的优势。 (减少缓存未命中/占用的缓存行数。)尤其是对于 32 位用户空间,如果您不能仅将空选择器 (0) 用于其 SS/DS/ES。

但是如果整个 GDT 是 8 个或更少条目,则整个内容都适合一个缓存行(如果您将开头对齐 64)。较旧的 CPU(在 Pentium 4 / Core 2 之前)有 32 字节的缓存线,但不支持 64 位模式,因此需要的 GDT 条目更少。

请注意,CPU 永远不会真正访问索引 0,因此您可以将第一个“真实”GDT 条目和lgdt 与该地址减去 8 对齐。(“空描述符”是一种特殊情况。)

【讨论】:

请注意(对于保护模式和长模式)sysenter/sysexitsyscall/sysret 都希望它们使用的 GDT 条目位于特定的(“内核 CS,内核数据、用户 CS、用户数据”)顺序。 CPU 也不会访问空描述符 - 如果确保“&gdt[1]”与缓存行的开头对齐,则可以在缓存行中包含“8 个条目,不包括空”(总共 9 个条目) (并且未使用的“&gdt[0]”未对齐)。 @Brendan:谢谢,已更新。如果有什么比我目前的回答更多的内容,也许你应该写一个答案,详细说明这些说明如何/为什么需要(或至少是一个好主意)以某种方式布置 GDT。 @Brendan 能否请您指出 AMD 或 Intel 手册中描述此命令的部分? @OmarDarwish:对于(去年版本的)英特尔手册,它将是“第 5.8.7 节使用 SYSENTER 和 SYSEXIT 指令执行对系统过程的快速调用”和“第 5.8.8 节快速系统”以 64 位模式调用”。对于(更旧版本的)AMD 手册,它是“第 6.1 节快速系统调用和返回”。对于您拥有的任何版本的手册,相关部分都可能在其他地方(由于其他更改而重新编号) - 最好仅在系统程序员指南(针对两家制造商)中搜索单词 sycall sysretsysexit 要求 GDT 排列相同的说法并不完全正确。返回 64 位用户代码时,sysretCS 设置为IA32_STAR[48:63] + 16,将SS 设置为+ 8,这意味着用户数据必须放在首位。我认为他们这样做是为了让您可以在保护模式和长模式下使用相同的 GDT(内核 CS、内核数据、用户 32 位 CS、用户数据、用户 64 位 CS)。

以上是关于是否有关于如何布置全局描述符表条目的约定?的主要内容,如果未能解决你的问题,请参考以下文章

GDT全局描述符表

进入保护模式

execve() 和共享文件描述符

全局描述符表GDT

文件描述符表和系统调用

Bran的内核开发教程(bkerndev)-07 中断描述符表(IDT)