CPU如何知道哪个物理地址映射到哪个虚拟地址?

CPU如何知道哪个物理地址映射到哪个虚拟地址?

根据我的理解,每个进程通过虚拟地址而不是物理地址访问内存,而CPU负责通过MMU单元将这些虚拟地址转换为物理地址,并且两个或多个进程可以具有相同的虚拟地址。

那么我们说工艺A正在尝试访问虚拟地址12345,并且工艺B正在尝试访问虚拟地址12345

MMU将如何将每个进程的虚拟地址转换为物理地址,它是否为每个进程提供一个将虚拟地址映射为物理地址的映射表(因为我认为CPU甚至不知道“进程”是什么,它唯一的责任就是盲目地执行指令,而不关心哪条指令属于哪一个进程,而“进程”只是一个操作系统概念)?

答案1

内存管理单元访问描述如何将虚拟地址转换为物理地址的表。 (它不需要将物理地址转换为虚拟地址,这通常是不可能的,因为同一个物理地址可以通过多个虚拟地址访问或者可以取消映射。)该表的布局取决于CPU架构,但一般原理始终是相同的:有一个 CPU 寄存器,其中包含表的物理地址,其中包含其他表的物理地址,依此类推(现有架构上总共 2 到 4 层),直到表的级别包含数据所在的物理地址。在每个级别,使用表的哪个元素由虚拟地址中的某些位确定。

MMU 不了解操作系统进程本身。当CPU切换到执行不同的进程时,即当上下文切换发生这种情况时,操作系统的上下文切换代码的​​工作就是根据需要更新 MMU 表。实际上,我认为所有 Unix 系统都会在内存中为每个进程保留一份表的副本,并且只需更新 MMU 寄存器以指向当前进程的顶级表。

实际上,MMU 中有一部分关心操作系统进程:TLB。在 MMU 表中查找条目的成本相当高,因为它涉及多次内存访问。 TLB 是这些查找的缓存。在上下文切换时,操作系统必须使 TLB 无效(即删除所有缓存条目),因为新进程的映射会有所不同。许多架构允许操作系统在每个 MMU 表条目中放置一个指示符来表示“该条目属于进程 N”。如果 TLB 条目包含的进程号不是当前进程号,则跳过该条目。 CPU 寄存器包含当前进程号,上下文切换代码会更新它。这种机制意味着 TLB 可以同时包含有关多个进程的信息,从而提高了在这些进程之间来回切换时的性能。由于可用于存储 N 的位通常少于存储所有操作系统进程 ID 所需的位,因此 N 不是进程 ID,而是操作系统为此目的生成的数字,并且如果使用的话,该数字会随着时间而变化。

答案2

在 Linux 中,内核维护一个五级页表(无论 CPU 的功能如何;多余的级别在编译时会被删除)。最顶层是页面全局目录,每个进程都有自己的目录,pgdmm_struct。这样每个进程都可以有自己的映射,所以不同进程中的地址12345指向不同的物理地址。

CPU 并不真正了解进程,但它们确实具有支持进程的功能。在 x86 类型的 CPU 上,有各种与任务相关的功能,但它们实际上往往被忽略。由于进程调度由内核管理,因此它本身可以跟踪页表更改,并在切换任务时更新切换到新进程页表所需的任何 CPU 状态。在 x86 PC 上,这涉及更新CR3控制寄存器指向页目录。

页表管理梅尔·戈尔曼的章节了解 Linux 虚拟内存管理器本书给出了很好的概述。

答案3

操作系统中的每个进程都有一个称为 PCB 的数据结构:https://en.wikipedia.org/wiki/Process_control_block

PCB 包含 - 以及其他一些内容 - 页表、内存限制、段表的信息(取决于操作系统使用的内存)。请注意,PCB 是一种按进程的数据结构,每个进程都有一个。

虚拟内存地址12345分为page+ offset- 比如说,123页号和45偏移量。对于每个进程,都会查阅其页表以在物理内存中查找等效的页(称为帧)。

考虑到以上几点,即使虚拟地址相同,物理地址也会不同。

由于在翻译每个页面时查找页表可能会非常慢,因此 MMU 为最近翻译的页面保留了缓存。称为翻译后备缓冲区(TLB):https://en.wikipedia.org/wiki/Translation_lookaside_buffer

相关内容