-
Notifications
You must be signed in to change notification settings - Fork 25
/
ch17s04.html
3 lines (3 loc) · 8.56 KB
/
ch17s04.html
1
2
3
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>4. MMU</title><link rel="stylesheet" href="styles.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><link rel="start" href="index.html" title="Linux C编程一站式学习" /><link rel="up" href="ch17.html" title="第 17 章 计算机体系结构基础" /><link rel="prev" href="ch17s03.html" title="3. 设备" /><link rel="next" href="ch17s05.html" title="5. Memory Hierarchy" /></head><body><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">4. MMU</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ch17s03.html">上一页</a> </td><th width="60%" align="center">第 17 章 计算机体系结构基础</th><td width="20%" align="right"> <a accesskey="n" href="ch17s05.html">下一页</a></td></tr></table><hr /></div><div class="sect1" lang="zh-cn" xml:lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="id2767055"></a>4. MMU</h2></div></div></div><p>现代操作系统普遍采用虚拟内存管理(Virtual Memory Management)<a id="id2767066" class="indexterm"></a>机制,这需要处理器中的MMU(Memory Management Unit,内存管理单元)<a id="id2767076" class="indexterm"></a>提供支持,本节简要介绍MMU的作用。</p><p>首先引入两个概念,虚拟地址和物理地址。如果处理器没有MMU,或者有MMU但没有启用,CPU执行单元发出的内存地址将直接传到芯片引脚上,被内存芯片(以下称为物理内存,以便与虚拟内存区分)接收,这称为物理地址(Physical Address,以下简称PA)<a id="id2767100" class="indexterm"></a>,如下图所示。</p><div class="figure"><a id="id2767109"></a><p class="title"><b>图 17.5. 物理地址</b></p><div class="figure-contents"><div><img src="images/arch.pabox.png" alt="物理地址" /></div></div></div><br class="figure-break" /><p>如果处理器启用了MMU,CPU执行单元发出的内存地址将被MMU截获,从CPU到MMU的地址称为虚拟地址(Virtual Address,以下简称VA)<a id="id2767128" class="indexterm"></a>,而MMU将这个地址翻译成另一个地址发到CPU芯片的外部地址引脚上,也就是将VA映射成PA,如下图所示。</p><div class="figure"><a id="id2767139"></a><p class="title"><b>图 17.6. 虚拟地址</b></p><div class="figure-contents"><div><img src="images/arch.vabox.png" alt="虚拟地址" /></div></div></div><br class="figure-break" /><p>如果是32位处理器,则内地址总线是32位的,与CPU执行单元相连(图中只是示意性地画了4条地址线),而经过MMU转换之后的外地址总线则不一定是32位的。也就是说,虚拟地址空间和物理地址空间是独立的,32位处理器的虚拟地址空间是4GB,而物理地址空间既可以大于也可以小于4GB。</p><p>MMU将VA映射到PA是以页(Page)<a id="id2767172" class="indexterm"></a>为单位的,32位处理器的页尺寸通常是4KB。例如,MMU可以通过一个映射项将VA的一页0xb7001000~0xb7001fff映射到PA的一页0x2000~0x2fff,如果CPU执行单元要访问虚拟地址0xb7001008,则实际访问到的物理地址是0x2008。物理内存中的页称为物理页面或者页帧(Page Frame)<a id="id2767190" class="indexterm"></a>。虚拟内存的哪个页面映射到物理内存的哪个页帧是通过页表(Page Table)<a id="id2767199" class="indexterm"></a>来描述的,页表保存在物理内存中,MMU会查找页表来确定一个VA应该映射到什么PA。</p><p>操作系统和MMU是这样配合的:</p><div class="orderedlist"><ol type="1"><li><p>操作系统在初始化或分配、释放内存时会执行一些指令在物理内存中填写页表,然后用指令设置MMU,告诉MMU页表在物理内存中的什么位置。</p></li><li><p>设置好之后,CPU每次执行访问内存的指令都会自动引发MMU做查表和地址转换操作,地址转换操作由硬件自动完成,不需要用指令控制MMU去做。</p></li></ol></div><p>我们在程序中使用的变量和函数都有各自的地址,程序被编译后,这些地址就成了指令中的地址,指令中的地址被CPU解释执行,就成了CPU执行单元发出的内存地址,所以在启用MMU的情况下,程序中使用的地址都是虚拟地址,都会引发MMU做查表和地址转换操作。那为什么要设计这么复杂的内存管理机制呢?多了一层VA到PA的转换到底换来了什么好处?All problems in computer science can be solved by another level of indirection.还记得这句话吗?多了一层间接必然是为了解决什么问题的,等讲完了必要的预备知识之后,将在<a class="xref" href="ch20s05.html#link.vm">第 5 节 “虚拟内存管理”</a>讨论虚拟内存管理机制的作用。</p><p>MMU除了做地址转换之外,还提供内存保护机制。各种体系结构都有用户模式(User Mode)<a id="id2767273" class="indexterm"></a>和特权模式(Privileged Mode)<a id="id2767280" class="indexterm"></a>之分,操作系统可以在页表中设置每个内存页面的访问权限,有些页面不允许访问,有些页面只有在CPU处于特权模式时才允许访问,有些页面在用户模式和特权模式都可以访问,访问权限又分为可读、可写和可执行三种。这样设定好之后,当CPU要访问一个VA时,MMU会检查CPU当前处于用户模式还是特权模式,访问内存的目的是读数据、写数据还是取指令,如果和操作系统设定的页面权限相符,就允许访问,把它转换成PA,否则不允许访问,产生一个异常(Exception)<a id="id2767307" class="indexterm"></a>。异常的处理过程和中断类似,不同的是中断由外部设备产生而异常由CPU内部产生,中断产生的原因和CPU当前执行的指令无关,而异常的产生就是由于CPU当前执行的指令出了问题,例如访问内存的指令被MMU检查出权限错误,除法指令的除数为0等都会产生异常。</p><div class="figure"><a id="id2767327"></a><p class="title"><b>图 17.7. 处理器模式</b></p><div class="figure-contents"><div><img src="images/arch.cpumode.png" alt="处理器模式" /></div></div></div><br class="figure-break" /><p>通常操作系统把虚拟地址空间划分为用户空间和内核空间,例如x86平台的Linux系统虚拟地址空间是0x00000000~0xffffffff,前3GB(0x00000000~0xbfffffff)是用户空间,后1GB(0xc0000000~0xffffffff)是内核空间。用户程序加载到用户空间,在用户模式下执行,不能访问内核中的数据,也不能跳转到内核代码中执行。这样可以保护内核,如果一个进程访问了非法地址,顶多这一个进程崩溃,而不会影响到内核和整个系统的稳定性。CPU在产生中断或异常时不仅会跳转到中断或异常服务程序,还会自动切换模式,从用户模式切换到特权模式,因此从中断或异常服务程序可以跳转到内核代码中执行。事实上,整个内核就是由各种中断和异常处理程序组成的。总结一下:在正常情况下处理器在用户模式执行用户程序,在中断或异常情况下处理器切换到特权模式执行内核程序,处理完中断或异常之后再返回用户模式继续执行用户程序。</p><p>段错误我们已经遇到过很多次了,它是这样产生的:</p><div class="orderedlist"><ol type="1"><li><p>用户程序要访问的一个VA,经MMU检查无权访问。</p></li><li><p>MMU产生一个异常,CPU从用户模式切换到特权模式,跳转到内核代码中执行异常服务程序。</p></li><li><p>内核把这个异常解释为段错误,把引发异常的进程终止掉。</p></li></ol></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ch17s03.html">上一页</a> </td><td width="20%" align="center"><a accesskey="u" href="ch17.html">上一级</a></td><td width="40%" align="right"> <a accesskey="n" href="ch17s05.html">下一页</a></td></tr><tr><td width="40%" align="left" valign="top">3. 设备 </td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top"> 5. Memory Hierarchy</td></tr></table></div></body></html>