内核中与驱动相关的内存操作之一(MMU)

1.MMU的存在意义:

    MMU(Memory Manage Unit)的出现是为了解决以下这类问题的一种"硬件算法"或者说策略:16MB的程序运行于4MB内存空间的问题,实现内存的更高效地利用.类比于现实生活中的银行.银行无须要保障每时每刻都准备充足以备所有用户同时取钱--这种情况基本上不会发生.通过挖东墙补西墙,实现资金的更高效利用.从而达到一种"动态平衡",而使人表面上看到的是"静止"的.

    1-1.虚拟地址:

    虚拟地址是指CPU物理寻址能力的地址范围,通常是PC指针的大小.它是由CPU的位数决定的,比如32位的CPU,它的物理寻址能力为0x0000 0000 ~ 0xffff ffff(2^32 = 4G).

    1-2.物理地址:

    和虚拟地址相对立,和实际设备相对应.比如256MB的32位的CPU而言,它的有效的物理空间为0x000000000~0x0FFFFFFF(256MB).物理地址有效访问范围为:基地址 ~ 基地址 + 0x0fffffff.

    物理地址是虚拟地址的一个子集.

    1-3.虚拟地址到物理地址的投射:

    我们实际的数据交互都没办法离开实质的物质存在作为载体.比如我们的物理地址范围为[BASE,BASE + 0x0FFFFFFF],如果代码操作在此区间之外的虚拟地址的话,必须要把这个虚拟地址投影到[BASE,BASE + 0x0FFFFFFF]这个范围之内.这工作由MMU完成.比如LINUX是一个虚拟内存的OS,操作的都是虚拟地址,因此必须要转化为物理地址去实现物理设备的操作.因此,它的宏观流程如下: 

虚拟地址-->MMU-->物理地址

2.页和页框:

    2-1.页(page):

    任何东西都存在其最基本单元,而虚拟地址以"页"为其基本单元.对于内核而言,页大小大多数平台架构下都是4KB.

    2-2.页框(frame):

    页框是实质物理地址空间的基本单元.

    虚拟地址和物理地址交互单元是"页<-->页框".就是说,虚拟地址上的"页"要和物理地址的"页框"相对应.因此,它们的大小必须相等.但是虚拟地址上的"页"和物理地址哪个"页框"关联,其过程是动态的,里面有硬件算法,而这种硬件算法的实现,就是由MMU去实现的.MMU一般是CPU里面的一个IP(内置外设).如下图所示:

   


    虚拟地址上的页被投影到物理地址上的哪一个页框是不定的,因此,页必须知道一种"信息"用来获取页是否可以被投影?如果多个页框可以被投影,那么选哪一个页框比较好?因此,页至少包含两部分信息:页期望投影到哪页框上?期望投影到的页框是否有效?对应页的"Frame Index | P".下面给出几个实例描述这一过程:


例一:

MOVE REG,0 //将0号地址的值传递进寄存器REG

    虚拟地址0将被送往MMU,MMU看到该虚地址落在页0范围内(页0范围是0到4095)从上图我们看到页0所对应(映射)的页框为2(页框2的地址范围是8192到12287),因此MMU将该虚拟地址转化为物理地址8192,并把地址8192送到地址总线上.内存对MMU的映射一无所知,它只看到一个对地址8192的读请求并执行它.MMU从而把0到4096的虚拟地址映射到8192到12287的物理地址.

例二:

MOVE REG,8192

  因为虚拟地址8192在页2中,而页2被映射到页框6(物理地址从24576到28671).因此,上述这条语句被转换为下面的语句:

MOVE REG,24576

例三:

MOVE REG,20500

    虚拟地址20500在虚页5(虚拟地址范围是20480到24575)距开头20个字节处,虚页5映射到页框3(页框3的地址范围是 12288到16383),于是被映射到物理地址12288+20=12308.因此,上述这条语句被转换为下面的语句:

MOVE REG,12308

例四:

MOV REG,32780

    从上图中我们可以看到,我们只有8个页框(物理地址),但我们有16个页(虚拟地址),所以我们只能把16个页中的8个进行映射.虚拟地址32780落在页8的范围内,从上图总我们看到页8没有被有效的进行映射(该页被打上X),这是又会发生什么?MMU注意到这个页没有被映射,于是通知CPU发生一个缺页故障(page fault).这种情况下操作系统必须处理这个页故障,它必须从8个物理页框中找到1个当前很少被使用的页框并把该页框的内容写入外围存储器(这个动作被称为page copy),随后把需要引用的页(例4中是页8)映射到刚才释放的页框中(这个动作称为修改映射关系),然后从新执行产生故障的指令(MOV REG,32780).假设操作系统决定释放页框1,那么它将把虚页8装入物理地址的4-8K,并做两处修改:首先把标记虚页1未被映射(原来虚页1是被影射到页框1的),以使以后任何对虚拟地址4K到8K的访问都引起页故障而使操作系统做出适当的动作(这个动作正是我们现在在讨论的),其次他把虚页8对应的页框号由X变为1,因此重新执行MOV REG,32780时,MMU将把32780映射为4108.

 

3.虚拟地址值的意义:

  和内核打交道的地址都是虚拟地址,这个虚拟地址每个bit都是有意义的.对MMU来说,这个虚拟地址就相当于一张索引图,MMU通过这张图为我们找到相应的有效的物理地址.很多使用虚拟存储技术的现代系统,都采用了分页技术.把虚拟地址空间分成大小相同的一组页,每个页必须有唯一的标识号.在实际编程中,我们并不是以页为单位的,而是以字节为单位的,所以还要一个偏移数据位段.因此,对于MMU而言,虚拟地址分两部分:

PageIndex|Offset

  两者并起来就是CPU的位数,如32位.PageIndex是页的索引值,而Offset即为选定页的偏移量.如ARM平台的LINUX内核页大小一般为4KB,因此,如果以字节为单位的话,必须要有12bit来表征其偏移量Offset(2^12 = 4KB).而页的数目,32bit的CPU其虚拟空间为4GB(2^32=4GB),以4KB为页大小的话,则有4GB/4KB=2^20个页.为了保证页的唯一性,需要20bit来表征PageIndex.如下:

PageIndex|Offset = [31,12] | [11,0]

    当操作一个虚拟地址的时候,MMU会根据这两部分作为索引位图去找到相应的有效的物理地址.这里需要注意的是,虚拟地址并不是直接转换为物理地址的,中间还要经过一个"表",这个表就是转换表--"TranslateTable".这张表记录的才是虚拟地址到物理地址的索引.细则如下:

  虚拟地址-->[MMU]-->TTB-->物理地址

   因此,下面将对TTB的功能进行描述.

 

4.TTB和TLB:

  4-1.TTB(TranslateTable):

  TTB是协助MMU完成虚拟地址到物理地址投影、内存的访问权限和设置虚拟存储空间缓冲的重要手段.TTB每一行代表一个页信息,里面包含了虚页到实页转换需要的所有信息,如如何投影的、访问权限等.TTB存在于内存当中,它的基本单位为地址变换条目,即"entry".在ARM体系当中,TTB在内存中的地址被记录在协处理器CP15的C2寄存器中.

  4-2.TLB(Translate Lookside Table):

  从虚拟地址到物理地址的变换过程其实是查表的过程.内存的使用是最广最频繁的,像LINUX这样的虚拟存储系统,把虚拟地址变换为物理地址的过程是很频繁的,如果页表是存放在内存当中,这种代价也是很大的.作为一种硬件优化策略,CPU内置了一个叫TLB的RAM段.TLB相当于CPU内置的RAM,容量比较小,比较小的为8~16个字节,这个RAM段的访问速度相当快,和CPU访问寄存器的速度相当.里面存放的是地址变换条目.因此,虚拟地址到物理地址的过程进一步细化如下:

虚拟地址-->[MMU]-->TLB-->TTB-->物理地址

  TLB把经常访问的虚拟地址和物理地址建立起一种投影关系.当CPU请求存储访问时,首先在TLB查找虚拟地址,进一步找到此虚拟地址对应的条目,如果找到此虚拟地址对应的条目,即可投影到相应的物理地址.否则只能从TTB查找,然后更新到TLB.如果TLB满的话,通过硬件算法,需要对TLB上的条目进行淘汰.

 

5.条目(entry):

  条目(entry)包含了虚拟地址到物理地址的所有信息体,比如虚页应该投影到哪个实页,内存访问的结果等等.当CPU处理一个虚拟地址,无论是TTB还是TLB,最终都要落实到条目去索引相应的实页.条目,可以说是虚拟地址到物理地址转向的"核心数据"单元.它是虚拟存储空间中一块连续的存储空间被映射成物理存储空间中同样大小的一块连续存储空间的"依据".

  5-1.内存块:

   MMU进行映射时,是以"块"为基本单位来进行映射的.ARM支持的存储块的以下四种:

1).段(section):大小为1M;
2):大页(LargePages):大小为16KB;
3).小页(SmallPages):大小为4KB;
4).极小页(TinyPages):大小为1KB;

  通过配置相关的协处理器寄存器,可以选择"块"的尺寸.

  5-2.描述符

  协处理器的C2保存了TTB的基地址.类比于一个数组,此数组的基地址存放在C2寄存器上,数组里面的每一个元素笼统地称之为"条目(Entry)".而我们的数组是有元素的,每个元素都是有类型的,比如说int型,char型,甚至是结构体等.因此,TTB里面每个元素笼统叫法是"条目(Entry)",更准确的叫法为"描述符",而描述符再具体而分,分为"一级描述符"和"二级描述符".和数组里面的元素一样,描述符也是有地址的,分别为"一级描述符地址"、"二级描述符地址".通过地址,我们可以索引到数组元素(描述符).

  如果某CPU被配置成一级页表转换的话,TTB可以理解为一个一维数组.这个一维数组里面每一个元素都是"一级描述符".通过解析"一级描述符",可以得到物理地址;如果某CPU被配置成二级页表转换的话,TTB可以理解为一个二维数组,要想访问某一元素,必须先检索到此元素所在的"子数组(一级描述符)"里面,在"子数组"里面再去检索"目标元素(二级描述符)".通过解析二级描述符可以得到物理地址.

  无论是一级描述符还是二级描述符,都可以笼统地称之为"条目".和数组一样,每个元素都是有地址的.访问数组里面的元素我们可以通过地址索引的方式实现.同样,访问TTB里面的条目也是通过地址索引的方式来实现的.描述符的地址在ARM核里面是有这样的规定:

一级页表的描述符地址 = TTB[31,14] | (VA[31,20] >> 14) | [1,0]

  CP15的寄存器C2的[31,14]和虚拟地址的[31,20]并凑成一个32位数的高30位,低两位为00b,从而形成一个32位的索引值,通过该索引可以从页表中查到一个4字节的地址变换条目.该条目中或者包含了一个一级描述符,或者包含了一个指向二级页表的指针.注意,这里我们仅仅找到的是"条目",至于这个条目里面的信息是什么,需要我们根据具体的协处理配置去解析--到底是一级描述符还是指向二级页表的指针.

  一级页表地址转换:

  一级页表地址转换对应了一级描述符,而一级描述符根据上述索引的32位数的最低两位,可以分为四种可能.如下:

  下面以一级描述符为段描述符为例,即32位地址索引的最低两位为10b.CPU核发出一个VA(虚拟地址),MMU截取VA[31,20]并结合TLB/TTB[31,14]索引到此段描述符的地址,从而索引到此段描述符的内容,如下:

 

 

  该段描述符的bit[31,20]对应了物理段(一共12bit,32位的CPU的可访问物理空间为2^32=4G.一个段为1M.2^12=4096个段.)

  得到了对应的物理段地址后,再通过VA的偏移地址结合得到物理地址PA.其过程如下:

 

 

  二级页表地址转换:

  二级页表地址转换,即一级描述符里面记录并不是物理地址,而是二级描述符的索引.通过一级描述符索引到二级描述符,再通过二级描述符找到相应的物理地址.以大页为例,其实质也是以地址为索引:



 












   

  

   




发布了131 篇原创文章 · 获赞 17 · 访问量 19万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章