为什么 x86 CPU 仅使用 4 个环中的 2 个?

为什么 x86 CPU 仅使用 4 个环中的 2 个?

因此,基于 Linux 或 Windows 的 x86 系统仅将 Ring 0 用于内核模式,将 Ring 3 用于用户模式。既然处理器最终都只使用其中两个,那为什么还要区分四个不同的 Ring?AMD64 架构上的情况有变化吗?

答案1

主要有两个原因。

第一个原因问题是,尽管 x86 CPU 确实提供了四环内存保护,但由此提供的保护粒度仅限于每个段级别。也就是说,每个段可以设置为从 0 到 3 的特定环(“特权级别”),以及其他保护,例如写禁用。但可用的段描述符并不多。大多数操作系统都希望拥有更精细的内存保护粒度。比如...针对单个页面。

因此,基于页表条目 (PTE) 的保护应运而生。大多数(如果不是全部)现代 x86 操作系统或多或少会忽略分段机制(无论如何,它们会尽可能地忽略分段机制),并依赖于基于 PTE 的保护。这是由标志位指定的,标志位是每个 PTE 中的低 12 位 - 加上支持不执行的 CPU 上的位 63。每个页面都有一个 PTE,通常为 4K。

其中一个标志位称为“特权”位。该位控制处理器是否必须处于“特权”级别之一才能访问页面。“特权”级别为 PL 0、1 和 2。但它只是一个位,因此在逐页保护级别,就内存保护而言,可用的“模式”数量只有两种:页面可以从非特权模式访问,或者不能。因此只有两个环。

为了使每个页面有四个可能的环,它们必须在每个页表条目中有两个保护位,以对四个可能的环号之一进行编码(就像段描述符一样)。但事实并非如此。

第二个原因是操作系统可移植性的目标。这不仅仅与 x86 有关;Unix 教会我们,操作系统可以相对移植到多种处理器架构,这是一件好事。有些处理器仅支持两个环。通过不依赖架构中的多个环,操作系统实现者使操作系统更具可移植性。

还有第三个原因这是 Windows NT 开发所特有的。NT 的设计者(David Cutler 及其团队,微软从 DEC 西部地区实验室挖来的人)在 VMS 方面拥有丰富的经验;事实上,Cutler 和其他几个人都是 VMS 的原始设计者。而 VMS 所设计的 VAX 处理器(反之亦然)确实有四个环。VMS 使用四个环。(事实上,VAX 在 PTE 中有四个保护位,允许“从用户模式只读,但可从环 2 和内部写入”这样的组合。但我离题了。)

但是,在 VMS 的 Ring 1 和 Ring 2 中运行的组件(分别是记录管理服务和 CLI)被排除在 NT 设计之外。VMS 中的 Ring 2 实际上与操作系统安全无关,而是与将用户的 CLI 环境从一个程序保留到另一个程序有关,而 Windows NT 根本没有这个概念;CLI 作为普通进程运行。至于 VMS 的 Ring 1,Ring 1 中的 RMS 代码必须经常调用 Ring 0,而 Ring 转换的成本很高。事实证明,直接转到 Ring 0 并完成它比在 Ring 1 代码中进行大量 Ring 0 转换要高效得多。(再次强调 - 无论如何,NT 都没有类似 RMS 的东西。)

但是他们为什么在那里呢?至于为什么 x86 实现了四个环而操作系统没有使用它们 - 你谈论的是比 x86 设计更新的操作系统。x86 的许多“系统编程”功能早在 NT 或真正的 Unix 式内核在其上实现之前就设计好了,他们真的不知道操作系统会使用什么。(直到我们在 x86 上实现了分页 - 直到 80386 才出现 - 我们才可以实现真正的 Unix-ish 或 VMS 类内核,而无需从头开始重新考虑内存管理。

现代 x86 操作系统不仅在很大程度上忽略了分段(它们只是设置了基地址为 0 且大小为 4 GB 的 C、D 和 S 段;F 和 G 段有时用于指向关键操作系统数据结构),它们还在很大程度上忽略了诸如“任务状态段”之类的内容。TSS 机制显然是为线程上下文切换而设计的,但事实证明它有太多副作用,因此现代 x86 操作系统“手动”执行。例如,x86 NT 唯一一次更改硬件任务是针对某些真正异常的情况,例如双重错误异常。

对于 x64,许多这些废弃的功能被忽略了。(值得赞扬的是,AMD 实际上与操作系统内核团队进行了交谈,并询问他们需要 x86 的什么、他们不需要或不想要什么以及他们希望添加什么。)x64 上的段仅以所谓的残留形式存在,不存在任务状态切换等。操作系统继续只使用两个环。

相关内容