为什么 x86 寻呼没有特权环的概念?

Why does x86 paging have no concept of privilege rings?

早在 1982 年,当 Intel 发布 80286 时,他们在分段方案(0-3 环)中添加了 4 个特权级别,由全局描述符 Table (GDT) 和局部描述符中的 2 位指定Table (LDT).

在 80386 处理器中,Intel 添加了分页,但令人惊讶的是,它只有 2 个权限级别(管理员和用户),由页面目录条目 (PDE) 和页面 Table 条目中的单个位指定(PTE).

这意味着仅使用分页的 OS(像大多数现代 OSes)无法从 ring 1 和 2 的存在中获益,这可能非常有用,例如, 对于司机。 (例如,Win9x 经常崩溃,因为它正在将有缺陷的未经检查的驱动程序加载到环 0 中)。

从可移植性的角度来看,ring 1 和 2 的存在是 x86 架构的一个怪癖,可移植 OSes 不应该使用它们,因为其他架构只有 2 个权限级别。

但我敢肯定,英特尔工程师在 1985 年设计 386 时并没有考虑到其他平台的可移植性。

那么为什么英特尔不允许分页有 4 个权限级别,比如分段?

386保护模式和286一样有四个权限级别(称为rings):ring 0权限最高(操作系统),ring 1和2使用不多,ring 3最低特权(用户应用程序)。环 0-2 称为“主管”,而环 3 称为“用户”。

根据代码段的描述符特权级(DPL),当前特权级(CPL)由您正在执行的指令的地址决定。有关当前权限级别的更多信息,请参阅

您所指的位如下。它是映射 4MB 页面(或引用页面 table 的 32 位 PDE)的 32 位页面目录条目 (PDE) 中的第 2 位。这个位称为“User/Supervisor”(U/S)。该位值为“0”表示不允许用户模式访问由该条目控制的 4MB 区域。正如您所写,这并不意味着只有“2 个特权级别(主管和用户)”。 “主管”级别仍然由三环组成。这包括,连同用户响铃,总共四个响铃。

参见 Intel 64 和 IA-32 架构软件开发人员手册第 4.6 节,第 3A 卷:系统编程指南,第 1 部分:

Every access to a linear address is either a supervisor-mode access or a user-mode access. For all instruction fetches and most data accesses, this distinction is determined by the current privilege level (CPL): accesses made while CPL < 3 are supervisor-mode accesses, while accesses made while CPL = 3 are user-mode accesses.

因此,CPL 可以是 0、1、2 和 3,有效地具有所有 4 个环。

请从上述手册中找到有关 U/S 标志的更多信息:

Some operations implicitly access system data structures with linear addresses [...] called implicit supervisor-mode accesses regardless of CPL. Other accesses made while CPL < 3 are called explicit supervisor-mode accesses. Access rights are also controlled by the mode of a linear address as specified by the paging-structure entries controlling the translation of the linear address. If the U/S flag (bit 2) is 0 in at least one of the paging-structure entries, the address is a supervisor-mode address. Otherwise, the address is a user-mode address.

P.S。我的回答没有解决为什么环 1 和环 0 之间没有与环 3 和环 0/1/2 之间相同的内存保护的问题,因此如果页面-[=,则环 1 和环 2 不可用32=]条目无法将它们与环0区分开。

我的一个猜测是英特尔打算当 Ring 1 代码为 运行 时,它 主管,“监督”ring 3 代码。不响1运行低于响0.

如果 ring 1 代码想调用 ring 0 代码,它可以通过调用门调用,ring 0 代码可以将 CR3 更改为包含物理页面映射的页面 table ' 出现在页面 table 正在使用环 1 或 2 代码。

我真的不太了解这些东西,但是 https://wiki.osdev.org/Task_State_Segment 显示 TSS 包含一个 CR3 字段,所以使用硬件任务切换我猜通过调用门调用可以直接触发 CR3 变化。 (所以调用目标 not 已经必须被映射,否则 ring 1 / 2 代码可能已经修改了它。或者它可以被映射为只读,连同页面 table 本身和 GDT,以阻止 ring 1 代码通过修改接管 ring 0。)

This means that an OS that only uses paging [...] unable to benefit from the existence of rings 1 and 2

那是你的错误:你不能“只使用分页”。即使让 user-space 的中断处理在正常的 x86 OS(具有平面内存模型)上工作,也需要设置 TSS 东西以在切换到内核模式时将 ESP 设置为内核堆栈指针,即使您不会以其他方式使用硬件任务切换。

x86 有“任务门”和“调用门”以及各种非常复杂的东西我希望我永远不必完全理解,但我希望花一些时间阅读它可能会有所启发关于 386 的架构师认为 OSes 可能想要做的事情。

与我之前的猜测不同(关于 ring 1 监督 ring 3),也许 Intel 希望 OSes 在同一页中使用分段将 ring 1 / 2 与 ring 0 内存分开 table如果需要1。正如您所说,他们可能并没有尝试创建一些东西,table 微内核 OSes 可以用作奖励。

内核可以决定虚拟地址 space 的布局,因此它可以很好地分配其中的块供 ring 1 代码使用,在调用它时适当地设置 CS/DS/ES/SS 。

不过,我认为这必须意味着非平面模型,因为 x86 分段会生成地址 go from 0..limit,而不是例如允许从 low..high 访问一系列虚拟地址而不改变指针的含义。

脚注 1:

ring 0和ring 1之间是否需要全内存保护? OS 可能将环 1 用于半可信代码。

一些特权指令需要 ring 0,因此 ring 1 可以防止意外发生。 IO 权限级别可以单独设置以允许 cliin/out in ring > 0,但其他指令如 invlpg, lgdt, and mov cr, reg 需要实际的 ring 0.

我们的愿望是保护东西不受其他东西的影响。在分页存在之前(以及在 80x86 存在之前 - “4 rings”模型可以追溯到 Multics,如果不是更早的话)最简单的方法是使用“rings”。

有了 4 个环,你可以有一个“D 不能访问 C,他们不能访问 B,他们都不能访问 A”的安排。这对于相反的方向来说是相对糟糕的(“C 可以访问 D 中的所有内容,无论它是否需要”)并且对于粒度来说是相对糟糕的(例如,如果你想要“C 可以访问 D 的一部分但不是 D 的全部”) .

通过分页,您可以为每个事物提供自己的虚拟地址 space 并将任何事物映射到任何地方以控制访问(因为您无法访问任何未映射到您的虚拟地址的事物 space).您仍然可以通过将属于 D 的所有页面映射到 A、B 和C;并将属于C的所有页面映射到A和B;等等。但是,您也可以有任何其他安排 - 例如模拟 10 个环而不是 4 个环,或者让 C 访问部分 D(但不是全部 D)和部分 B(但不是全部 B),或者...

那么问题就变成了;如果仅寻呼就足以模拟任意数量的振铃(甚至更多),为什么我们还有 2 个振铃?

答案是分页只控制对内存中的东西(代码、数据)的访问,而不t/can不控制对不在内存中的东西的访问(例如 CPU的控制寄存器)。仍然需要 2 个环来控制是否不在内存中的东西 can/can 不被访问(例如 mov cr0, eax 指令是否会导致一般保护错误)。

但是;有两件事使这一点不那么明显。在不同的虚拟地址 spaces 之间切换有一些与之相关的成本,人们试图将成本降到最低(例如,不给共享库自己单独的虚拟地址 spaces,不给单独的设备驱动程序他们自己的虚拟地址space,等等);并且因为分页被添加(考虑到向后兼容性)到一个预先存在的“4环分段”设计废料旧的“4环分段”仍在使用(例如TSS,IO许可系统等)。