type
status
date
slug
summary
tags
category
icon
password
Property
Apr 15, 2023 03:24 PM
在实现 CPU 虚拟化时,我们遵循的一般准则被称为受限直接访问(Limited DirectExecution,LDE)。LDE 背后的想法很简单:让程序运行的大部分指令直接访问硬件,只在一些关键点(如进程发起系统调用或发生时钟中断)由操作系统介入来确保“在正确时间,正确的地点,做正确的事”。为了实现高效的虚拟化,操作系统应该尽量让程序自己运行,同时通过在关键点的及时介入(interposing),来保持对硬件的控制。高效和控制是现代操作系统的两个主要目标。
关键问题在于:如何高效、灵活地虚拟化内存 如何实现高效的内存虚拟化?如何提供应用程序所需的灵活性?如何保持控制应用程序可访问的 内存位置,从而确保应用程序的内存访问受到合理的限制?如何高效地实现这一切?
我们利用基于硬件的地址转换(hardware-based address translation),简称为地址转换(address translation)。它可以看成是受限直接执行这种一般方法的补充。利用地址转换,硬件对每次内存访问进行处理(即指令获取、数据读取或写入),将指令中的虚拟(virtual)地址转换为数据实际存储的物理(physical)地址。因此,在每次内存引用时,硬件都会进行地址转换,将应用程序的内存引用重定位到内存中实际的位置。
当然,仅仅依靠硬件不足以实现虚拟内存,因为它只是提供了底层机制来提高效率。操作系统必须在关键的位置介入,设置好硬件,以便完成正确的地址转换。因此它必须管理内存(manage memory),记录被占用和空闲的内存位置,并明智而谨慎地介入,保持对内存使用的控制。同样,所有这些工作都是为了创造一种假象:每个程序都拥有私有的内存,那里存放着它自己的代码和数据。虚拟现实的背后是物理事实:许多程序其实是在同一时间共享着内存,就像 CPU(或多个 CPU)在不同的程序间切换运行。
通过虚拟化,操作系统(在硬件的帮助下)将丑陋的机器现实转化成一种有用的、强大的、易于使用的抽象。
假设
先假设用户的地址空间必须连续地放在物理内存中。同时,为了简单,我们假设地址空间不是很大,具体来说,小于物理内存的大小。最后,假设每个地址空间的大小完全一样。别担心这些假设听起来不切实际,我们会逐步地放宽这些假设,从而得到现实的内存虚拟化。
虚拟地址映射
用户进程在物理内存中并不是从 0 地址开始的
提示:介入(Interposition)很强大 介入是一种很常见又很有用的技术,计算机系统中使用介入常常能带来很好的效果。在虚拟内存中,硬件可以介入到每次内存访问中,将进程提供的虚拟地址转换为数据实际存储的物理地址。但是,一般化的介入技术有更广阔的应用空间,实际上几乎所有良好定义的接口都应该提供功能介入机制,以便增加功能或者在其他方面提升系统。这种方式最基本的优点是透明(transparency),介入完成时通常不需要改动接口的客户端,因此客户端不需要任何改动。
动态(基于硬件)重定位
思想很简单,称为基址加界限机制(base and bound),有时又称为动态重定位(dynamic relocation)。
具体来说,每个 CPU 需要两个硬件寄存器:
基址
(base)寄存器和界限
(bound)寄存器,有时称为限制
(limit)寄存器。这组基址和界限寄存器,让我们能够将地址空间放在物理内存的任何位置,同时又能确保进程只能访问自己的地址空间。
采用这种方式,在编写和编译程序时假设地址空间从零开始。但是,当程序真正执行时,操作系统会决定其在物理内存中的实际加载地址,并将起始地址记录在基址寄存器中。
当进程运行时,有趣的事情发生了。现在,该进程产生的所有内存引用,都会被处理器通过以下方式转换为物理地址:进程中使用的内存引用都是
虚拟地址
(virtual address),硬件接下来将虚拟地址加上基址寄存器中的内容,得到物理地址
(physical address),再发给内存系统。
将虚拟地址转换为物理地址,这正是所谓的地址转换(address translation)技术。也就是说,硬件取得进程认为它要访问的地址,将它转换成数据实际位于的物理地址。由于这种重定位是在运行时
发生的,而且我们甚至可以在进程开始运行后改变其地址空间,这种技术一般被称为动态重定位(dynamic relocation)。在动态重定位的过程中,只有很少的硬件参与,但获得了很好的效果。一个基址寄存器将虚拟地址
转换为物理地址,一个界限寄存器确保这个地址在进程地址空间的范围内。它们一起提供了既简单又高效的虚拟内存机制。
界限寄存器提供了访问保护。如果进程需要访问超过这个界限或者为负数的虚拟地址,CPU 将触发异常,进程最终可能被终止。界限寄存器的用处在于,它确保了进程产生的所有地址都在进程的地址“界限”中。这种基址寄存器配合界限寄存器的硬件结构是芯片中的(每个 CPU
一对
)。有时我们将CPU 的这个负责地址转换的部分统称为内存管理单元
(Memory Management Unit,MMU)。随着我们开发更复杂的内存管理技术,MMU 也将有更复杂的电路和功能。
关于界限寄存器再补充一点,它通常有两种使用方式。- 在一种方式中(像上面那样),它记录地址空间的大小,硬件在将虚拟地址与基址寄存器内容求和前,就检查这个界限。
- 另一种方式是界限寄存器中记录地址空间结束的物理地址,硬件在转化虚拟地址到物理地址之后才去检查这个界限。
这两种方式在逻辑上是等价的。简单起见,我们这里假设采用第一种方式。
转换示例
为了更好地理解基址加界限的地址转换的详细过程,我们来看一个例子。设想一个进程拥有 4KB 大小地址空间(是的,小得不切实际),它被加载到从 16KB 开始的物理内存中。一些地址转换结果见表 15.1。
从例子中可以看到,通过基址加虚拟地址(可以看作是地址空间的偏移量)的方式,很容易得到物理地址。虚拟地址“过大”或者为负数时,会导致异常。
补充:数据结构——空闲列表
操作系统必须记录哪些空闲内存没有使用,以便能够为进程分配内存。很多不同的数据结构可以用于这项任务,其中最简单的(也是我们假定在这里采用的)是空闲列表(free list)。它就是一个列表,记录当前没有使用的物理内存的范围。
硬件支持:总结
我们来总结一下需要的硬件支持(见表 15.2) 。首先,正如在 CPU 虚拟化的章节中提到的,我们需要两种 CPU 模式。操作系统在特权模式(privileged mode,或内核模式,kernelmode),可以访问整个机器资源。应用程序在用户模式(user mode)运行,只能做有限的操作。只要一个位,也许保存在处理器状态字(processor status word)中,就能说明当前的CPU 运行模式。在一些特殊的时刻(如系统调用、异常或中断),CPU 会切换状态。
硬件还必须提供
基址
和界限
寄存器(base and bounds register),因此每个 CPU 的内存管理单元(Memory Management Unit,MMU)都需要这两个额外的寄存器。用户程序运行时,硬件会转换每个地址,即将用户程序产生的虚拟地址加上基址寄存器的内容。硬件也必须能检查地址是否有用,通过界限寄存器和 CPU 内的一些电路来实现。硬件应该提供一些特殊的指令,用于修改基址寄存器和界限寄存器,允许操作系统在切换进程时改变它们。这些指令是
特权
(privileged)指令,只有在内核模式
下,才能修改这些寄存器。想象一下,如果用户进程在运行时可以随意更改基址寄存器,那么用户进程可能会造成严重破坏。最后,在用户程序尝试非法访问内存(越界访问)时,CPU必须能够产生
异常
(exception)。在这种情况下,CPU 应该阻止用户程序的执行,并安排操作系统的“越界”异常处理程序(exception handler)去处理。操作系统的处理程序会做出正确的响应,比如在这种情况下终止进程。类似地,如果用户程序尝试修改基址或者界限寄存器时,CPU 也应该产生异常,并调用“用户模式尝试执行特权指令”的异常处理程序。CPU 还必须提供一种方法,来通知它这些处理程序的位置,因此又需要另一些特权指令。
操作系统的职责
进程创建
时,操作系统从空闲列表
(free list)找到位置分配
内存空间,并标记为已用
进程终止
时,操作系统需要回收
内存到空闲列表
上下文切换
时,需要保存/加载
基址和界限寄存器
。比如放在进程结构或进程控制块 PCB 中。
当进程暂停时,操作系统可以切换其地址空间,只要分配新空间,拷贝,然后修改进程结构/PCB 里的基址寄存器就行
- 操作系统必须提供
异常处理程序
(exception handler),向硬件注册,当进程出现如越界访问等异常操作时,CPU 会执行这段异常处理程序,如终止该进程。
从表中可以看出,我们仍然遵循受限直接访问(limited direct execution)的基本方法,大多数情况下,操作系统正确设置硬件后,就任凭进程直接运行在 CPU 上,只有进程行为不端时才介入。
小结
- 本章通过虚拟内存使用的一种特殊机制,即地址转换(address translation),扩展了受限直接访问的概念。利用地址转换,操作系统可以控制进程的所有内存访问,确保访问在地址空间的界限内。这个技术高效的关键是硬件支持,硬件快速地将所有内存访问操作中的虚拟地址(进程自己看到的内存位置)转换为物理地址(实际位置)。所有的这一切对进程来说都是透明的,进程并不知道自己使用的内存引用已经被重定位。
- 一种特殊的虚拟化方式,称为基址加界限的动态重定位。基址加界限的虚拟化方式非常高效,因为只需要很少的硬件逻辑,就可以将虚拟地址和基址寄存器加起来,并检查进程产生的地址没有越界。基址加界限也提供了保护,操作系统和硬件的协作,确保没有进程能够访问其地址空间之外的内容。
- 这个简单的动态重定位技术有效率低下的问题。会产生内部碎片(internal ragmentation),指的是已经分配的内存单元内部有未使用的空间(即碎片),造成了浪费。
参考
- 作者:GJJ
- 链接:https://blog.gaojj.cn/article/blog-12
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。