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

use*_*989 6 linux cpu virtual-memory linux-kernel

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

因此,假设进程 A正在尝试访问虚拟地址12345,而进程 B正在尝试访问虚拟地址12345

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

Gil*_*il' 5

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

\n\n

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

\n\n

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

\n


Ste*_*itt 4

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

\n

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

\n

Mel Gorman\xe2\x80\x99s Understanding the Linux Virtual Memory Manager一书中的页表管理章节提供了很好的概述。

\n

  • 这是正确的。在 x86 CPU 上,设置 CR3 还会刷新 TLB,以便为新进程正确重新计算地址。 (2认同)