如今,几乎所有内核都使用 MMU 提供的虚拟内存。他们使用全局页表(其地址位于 CPU 寄存器中)以及页到进程的页管理器/映射器来实现此目的。例如,中的“vm”vmlinuz
表示Linux内核支持虚拟内存。
所有这一切都是可能的,因为 MMU 将连续的内存地址映射到 x86 架构所理解的内存段。
最初的 UNIX 内核确实有一个vmunix
版本,我相信它一定使用了类似的技术。然而,最初的 UNIX 内核是在 MMU 可用之前编写的。如果我没有记错的话,最初的 UNIX 内核(简称 UNIX 内核unix
)是在 x86 架构存在之前编写的。从历史上看,它确实在 PDP-9 和 PDP-11 上运行。
该内核如何执行内存寻址和管理?它是基于段的寻址(两个数字)还是完整的内存寻址(单个数字)?它如何在处理之间分离内存?
答案1
虚拟内存比 Unix 早近十年:在巴勒斯 B50001961年。它没有现代意义上的MMU(即基于页面),但提供了相同的基本功能。IBM System/360 型号 671965 年(比 Unix 还要古老)就有了 MMU。 Intel x86 处理器直到 1986 年的 80386 才获得 MMU。
实现 Unix 系统实际上并不需要 MMU。它确实需要某种形式的虚拟内存,否则实现fork
系统调用是极其困难的。fork
从第一个版本开始,通过复制现有进程来创建进程的系统调用就是 Unix 的基本组成部分,因此它确实需要虚拟内存。看DM Ritchie 和 K. Thompson,UNIX 分时系统,CACM,1974,§V“过程和图像”。
我不知道第一个 Unix 版本运行的硬件的细节,但它们确实有虚拟内存形式分段架构。 CPU 在程序取消引用的指针(虚拟地址)和内存中的实际位置(物理地址)之间进行转换。通过向虚拟地址添加偏移量来执行映射。在进程之间的每次上下文切换时,都会调整包含偏移量的寄存器。
尽管几乎所有 Unix 实现都提供进程隔离,但历史上一些没有内存保护的硬件实现并非如此(无论是在 20 世纪 70 年代,还是在 20 世纪 80 年代)迷你X8088 和 80286)。内存保护与地址虚拟化有些正交; MMU 可以同时提供这两种功能,而简单的分段架构则不能,MPU1 可以提供无需虚拟化的保护。对于没有 MMU 的系统,有一个 Linux 实现,uCLinux,但是由于缺少fork
很多程序无法运行(唯一支持的fork
是vfork
这需要一个execve
之后立即叫孩子进来)。
1 MPU(内存保护单元)记录每页内存的访问权限。
答案2
您不需要分页 MMU 来获得内存保护。
分页 MMU 解决了许多更高级的问题,例如内存碎片(大块不可用)和mmap
(仅在内存中保留文件最近使用的部分)。需要分页 MMU 来实现“统一页面缓存”,以缓存所有进程中的文件访问。
但基本的内存保护可以仅通过更简单的“分段”来完成,这可能适用于早期的 Unix 实现。例如,受保护的内核内存可以放置在执行用户模式代码时设置为“禁止访问”的段中。即使在现代分页操作系统 Linux 上,系统调用brk()
也是sbrk()
作为分段实现时代的兼容性保留而存在的。
本质上,分段有点像分页 MMU,只不过您只能获得固定数量的可变大小“页面”(实际上称为段),而不是可变数量的固定大小页面。
即使在今天,分段仍然存在于可能只有几千字节 SRAM 的低成本微控制器中,使得实现具有受保护内存的小型操作系统成为可能,尽管没有真正的分页 MMU。