(转载)虚拟化(5):地址翻译。

转自:https://zhuanlan.zhihu.com/p/38048773

首先先回顾了下cpu的LDE模式的思路,主要就是在大多数时间让程序直接在硬件上运行,但是在一些关键功能上,比如硬件访问,进程调度上能够让os得到控制,从而实现了高效运行的同时也能保证对系统的控制。

这一章要说的内存控制也是一样的思路,我们需要一些基本的硬件的支持,在这之上让os能够高效的实现vm.并且我们实现的vm也是需要有很好的扩展性,因为对程序来说,内存的变化是非常频繁的。

为了实现vm,我们会使用到地址翻译,也就是说程序看到的内存地址都是虚拟的,而实际的物理地址是由os来掌握的,当然单凭硬件是无法虚拟的,硬件只是提供了实现的基本支持,需要os会运用物理硬件的功能,加上软件的管理来记录实际物理地址的使用情况,提供对应的分配和回收内存的功能,从而实现在对内存加以控制的情况下的高效的虚拟化。

再次强调,我们要做的是实现一个美好的假象:让每个进程都能看到自己独立的,并且大小一致的地址空间。在这之下的各种盘根错节的处理都由os来进行。

首先从最基本的说起,我们先做几个简单的假设:

1.用户的地址空间在物理内存中是连续存储的

2.地址空间的大小不会大于物理内存

3.假设地址空间都是相等大小的

首先我们来介绍一种动态分配地址空间的方式:

比如这段代码

128: movl 0x0(%ebx), %eax ; load 0+ebx into eax

132: addl $0x03, %eax ; add 3 to eax register

135: movl %eax, 0x0(%ebx) ; store eax back to mem

如果要运行这个程序,首先需要加载到内存,这些代码的地址就是上面汇编代码最前面的数字。当要运行的时候,

1.先去地址为128处取出指令,然后执行,这条指令是按照寄存器ebx的内容作为地址,将地址空间中对应的内容取出放在寄存器eax中,假设ebx的内容是15K,那么从15k处取到了3000。

2.取出132处的指令,将eax中的数据加3,这样就变为了3003

3.取出135处的指令,将eax中的3003放到ebx指向的位置,也就是15K的地方,这样15K这个地址的数据就从3000变为了3003

上面看到的是这个进程的地址空间的信息,那么在整个系统中是什么样呢,答案就是下面这张图

 

 

 

从上图分配中可以看到,os在最开始的16KB中,我们上面所说的有三行代码的程序实际上是放在32KB到48KB这个区间段内的。代码中的地址是虚拟的,所以实际的地址是虚拟地址加上32KB的。这个也是个通用的模式:

物理地址=基地址+虚拟地址

所以cpu在执行每条指令的时候,实际都需要进行一个从虚拟地址到物理地址翻译的步骤,这个功能由一个单独的硬件完成,我们称之为MMU(memory management unit)。对于上面动态分配内存,我们需要2个寄存器来辅助完成地址翻译的过程,分别是基地址寄存器和界限寄存器(base and bound)。base 存储这个process 对应的基地址,bound存储地址空间的大小。

下面我们总结一下,为了完成上面的这种内存动态的分配,我们需要硬件和OS的哪些功能支持。

硬件模块提供的功能:

1.cpu提供特权模式和一般模式。这样就可以形成一种保护的机制,用户的process无法执行一些特权指令,从而让os能够对内存的实际管理得到控制。

2.base and bound register。这个上面说过,在翻译地址的时候用到。

3.有进行地址转换和校验的功能。也就是不仅要有上面说的寄存器,还要有用到这些寄存器的功能,也就是拿到一个虚拟的地址能有专门的硬件进行转换从而得到实际的物理地址。

4.提供特权指令对base and bound register 进行修改。

5.如果发生异常,需要特权指令来触发异常处理告诉os。

操作系统提供的功能:

1.对物理内存的管理,比如分配新内存,回收就内存等等。

2.在process 切换的时候能够更新base and bound 寄存器的内容

3.收到硬件的异常能对异常情况的处理(也就是os有些对应的代码,还记得之前说的trap table吗?)。

最后在书中有一个整体的流程图,理解这个很重要。

 

 

这个图是在之前加入时钟中断后的流程图的进一步扩充,主要就是加入了address translation的步骤,注意这个步骤是硬件自动完成的。

 

posted @ 2021-08-19 16:40  胖白白  阅读(160)  评论(0编辑  收藏  举报