转自:http://blog.csdn.net/martree/article/details/3321578

虚拟存储器的基本思想是程序,数据,堆栈的总的大小可以超过物理存储器的大小,操作系统把当前使用的部分保留在内存中,而把其他未被使用的部分保存在磁盘上。比 如对一个16MB的程序和一个内存只有4MB的机器,OS通过选择,可以决定各个时刻将哪4M的内容保留在内存中,并在需要时在内存和磁盘间交换程序片 段,这样就可以把这个16M的程序运行在一个只具有4M内存机器上了。而这个16M的程序在运行前不必由程序员进行分割。一个物理存储块(通常为一个页框)被多个逻辑页映射。
    
    伴随着这种技术的出现,“virtual address,即VA”和“physical address, 即PA”也就出现了。一般来说,CPU看到的地址是VA,VA是有地址线来决定的。比如,s3c2410是32位的SoC,那么它的寻址空间为 2^32=4GB,那么VA空间也就是4GB。但是在嵌入式系统中,物理存储器是不会有这么大的。现在这块s3c2410的实际内存SDRAM也就 64MB,远远小于4GB。也就是说,VA4GB,PA是64MB,PA的地址空间是VA地址空间的子集。既然PA没有VA那么大,而且CPU只能看到 VA,那么CPU如何找到PA呢?这也正是MMU的基本作用之一,就是提供VA到PA的转换机制,除了硬件的支持外,软件上实际就是维护一张表,表中的内 容是VA到PA的转换法则。由于有了MMU,那么就可以实现利用VA找到实际物理内存区域。具体的转换方法将在以后介绍。

现在讨论为什么要实现VA到PA的映射。就ARM而言,系统上电后,CPU的PC指向0x00000000或者0xffff0000,这是由CPU的设计 者决定的。在这个位置,一般安排非易失性存储器地址空间,比如rom,flash等。但是flash等响应速度慢,这就称为提高系统性能的一个瓶颈。而 sdram则具有很高的响应速度,为了提高系统运行速度,可以把flash中的应用程序下载到sdram中执行,也就是一个简单的loader的功能实 现。这样就出现一个问题,ARM响应exception时,程序指针指向固定的VA,比如,假设发生了IRQ中断,那么PC执行0x00000018(如 果是高端启动,则指向0xffff0018处。)但是此处仍然为非易失性存储器,也就是说,程序的一部分仍然在flash或者rom中执行。这时可以利用 MMU,把sdram的地址映射到0x00000000起始的一片连续地址空间,而把原来flash映射到其他不相冲突的存储空间位置。例如,flash 的地址范围0x00000000-0x00ffffff,sdram的地址范围0x30000000-0x31ffffff。那么可以把sdram映射到 0x00000000-0x1fffffff(此处地址空间未被占用)。映射完成后,如果处理器异常,假设依然为IRQ中断,pc指向 0x00000018,但是pc实际上是从物理地址0x30000018处读取指令。通过mmu的映射,可以实现系统运行的加速。这个地方也可以说明 bootloader中常见的中断向量表的设置,为什么有些使用b,有些使用ldr了。这个我们在基本指令使用中有着详细的描述。

在实际的应用过程中,还可能会把两片不连续的物理地址空间分配给sdram,而在os中,习惯上把sdram的空间连续起来,方便实现动态内存管理。通过mmu可以实现不连续的物理地址空间映射为虚拟地址空间。

 
    另外一个需求就是,实现不同的运行级别,那么一些关键的代码可以设定不被普通应用程序访问。这也是通过mmu控制访问权限来实现的。
 
    综上三个阶段所述,可见MMU的作用主要就是两个:
 
    · 实现VA到PA的映射(可以因此实现方便的动态内存管理)
    · 实现不同的访问权限。

结合s3c2410来分析MMU的几处硬件特点
 
    首先看看ARM920T的框图:
    可以验证前面的几个概念:
 
    ·位于中心的ARM9TDMI Processor Core发出的地址有两种,IVA和DVA,都是VA。其中I代表Instruction, D代表Data。也就是说,CPU核心看到的都是32bits的VA。
    ·Dcache、Icache、Dmmu、Immu看到的都是对应的MVA(modified virtual address),这个是比较复杂的地方,下面专门拿出这个来讲解。
    ·MMU处理后的输出地址都是对应的PA,通过AMBA Bus Interface连接到ASB总线上面。
 
    这样,从硬件上对地址的概念就比较清晰了。也可以很明显的看出MMU的功能:将VA转换成PA。但是现在存在的一个问题是,MVA是什么,为什么要用到MVA?
 
    可以看CP15协处理器的register 13。这个寄存器是进程识别寄存器,主要的操作如下:
 

Reading from CP15 register 13 returns the value of the process identifier. Writing CP15register 13 updates the process identifier to the value in bits [31:25]. Bits [24:0] should be zero.

 
    寄存器的字格式为:
 
    很清晰,ProcID为7bits,剩下的25bits should be zero,也就是可以实现2^25=32M的地址对齐。从这个道理上讲,每个进程拥有32M的MVA地址空间,而最多支持的进程数为2^7=128个。这 样,128*32M=4GB,正是全部的虚拟地址空间。但是,英文的datasheet上却并非如此,写的记录数字为64个进程,同样每个进程32M,怎 么可能达到4GB?参看下图:
 
 
    我觉得上图中的63应该改为127。因为这个63处不可能对应4GB,而应该对应2GB。判断此处属于datasheet的错误。
 
    还有,这个procID是何时,有谁写入的?有谁来维护?根据推断,在bootloader阶段,只需要一个进程就可以了,所以,procID一直都是复 位后默认的0,不需要改变。但是后面有了OS后,要想实现多进程,那么就需要对此维护了。所以procID的维护者是系统软件OS。在创建一个新进程的时 候,要把进程号写入procID。
 
    另外,关于MVA部分的转换公式,实际上还是有疑问的。
 

Addresses issued by the ARM9TDMI core in the range 0 to 32MB are translated by CP15 register13, the ProcID register. Address A becomes A + (ProcID x 32MB). It is this translated address that is seen by both the Caches and MMU. Addresses above 32MB undergo no translation.

 
    写成伪代码,可以参考《s3c2410完全开发》。
 

if VA < 32M then
        MVA = VA | (ProcID << 25)
else
        MVA = VA

 
    thisway.diy说利用PID来生成MVA的目的是为了减少切换进程时的代价:如果两个进程占用的VA有重叠,不进行上述处理的话,当进行进程切换 时必须进行VA到PA的重新映射,这就需要重新建立页表,使无效cache和TLB等等,代价很大。但是如果进行上述处理的话,进程切换就省事多了:假设 两个进程1、2运行时的VA都是0-32M,则它们的MVA分别是 (0x02000000-0x03ffffff)、(0x04000000-0x05ffffff),前面看到的MMU、cache使用MVA而不是使用 VA,这样就不必进行重建页表等工作了。
 
    但是这里带来的一个问题是,如果进程运行时的VA小于32M,那么根据PID的不同,可以达到4GB空间的任意部分,也就是,虽然可以避免运行VA小于 32M时的不同进程的“撞车”,但是同时带来的是VA小于32M可能与VA大于32M的进程产生了“撞车”。这样不是更为普遍吗?现在从原理上还不能理 解。翻看《ARM Architecture Reference Manual》,发现对于ARM核,如果采用MVA,那么进程切换实际上对应着Fast context switch extension,不知道原理是什么。对于研究bootloader来说,现在不设计到多进程,整个系统就是一个独立的单进程,PID就是默认的 0x0。这个问题可能要后推了。
 
四、提出几个问题
 
    1、在vivi中为什么使用了MMU?是否可以不用?
 
    这个问题已经解决。实际上,在nand flash启动的情况下,vivi中可以不使用MMU。因为一是中断向量表是放在sram里,响应速度比sdram还要快。另外,在bootloader 阶段,只有一个进程,不存在多进程的内存空间重叠的问题。也因为一个进程,所以单纯的PA就满足需求,没有必要用VA。开始时,也不需要区分访问权限。大 量的工作,比如进程切换、权限访问等等,都是在EOS中处理的。所以,这种情况下,可以不使用MMU。我把vivi中关于MMU的部分去除,编译下载,可 以正常引导内核启动,没有问题。
 
    那么,vivi为什么要开启MMU呢?原因也是比较简单的,就是追求系统运行的高效。因为s3c2410的Icache不受MMU的影响,而Dcache 和write buffer则必须开启了MMU功能之后,才能使用。而使用Dcache和write buffer后,对系统运行速度的提高是非常明显的,后面还将通过实验来验证这一点。也就是说,在nand flash启动时,vivi使用了MMU,主要是为了获得Dcache和write buffer的使用权,借此提高系统运行的性能。
 
    2、使用了MMU,那么软硬件是如何分工协作的?
 
    这个基本搞清楚了,但是还有一个遗留问题。针对于s3c2410,可以分为如下几个阶段:
 
    · 第一阶段  软件准备
 
    MMU在软件上的实现过程,实际上就是一个查表映射的过程。建立页表(translation table)是MMU功能的重要的一步。页表就是内存的一块区域,由一个个固定格式的entry组成。其中每个entry对应一个VA到PA的转换,每一 项的长度是一个word,还可以完成访问权限和缓冲特性的限定。在软件上,就是要把这个表填好。重映射就是修改相应的entry,改变了原来的映射规则, 很简单。
 
    这步工作是要软件提前准备的。需要注意的是,明确如何找到这个页表。对于表的查找,需要知道表的基地址和偏移地址,在cp15的register 2用于保存页表的基地址,这样就可以查找到相应的PA了。
 
    · 第二阶段 硬件完成VA-MVA
 
    硬件根据ARM9TDMI发出的VA和CP15的register 13来自动生成MVA。
 
    · 第三个阶段
 
    硬件自动实现cache查询,如果没有,则根据cp15的register 2和MVA找到translation table中的entry,实现相应的PA转换,读取内存,然后根据cache算法更新cache。也就是说,这个阶段也是硬件实现的。不过软件上对 cache要进行相应的管理,这个地方的算法相对还是比较复杂的。
 
    综上,对单进程而言,软件操作上就是维护translation table,并且处理好cache相关操作。
 
五、实验
 
    实验内容比较简单,综合了前面的串口实验,灯循环点亮实验,中断实验,nand flash实验,另外,加入了MMU功能。利用MMU功能的开启,观察灯循环点亮实验,如果开启了Dcache和write buffer,灯闪的速度明显快的多,几乎看不出间隔,而把其关闭,则还能够看出间隔。这还是在12MHz的前提下,还没有把PLL功能开启。如果把 PLL功能开启,还需要进行相应的调整。
 
    源代码如下,完全仿照vivi的架构,另外,mmu部分基本是采用vivi的源代码,具体的分析留待vivi源代码分析时解决。其实,如果开启了 mmu,cache和write buffer是否能够合理有效的使用还是一个问题。如果使用不当,带来的问题可能会比较奇怪,而且难以解决。在这个过程中,需要对照现有的较好的代码进行 分析,总结规律,然后应用到自己的设计中去。

最新文章

  1. codeforces 567D.One-Dimensional Battle Ships 解题报告
  2. 链接后加&quot;/&quot;与不加&quot;/&quot;的区别
  3. libevent源码分析:bufferevent
  4. 转:Java的各种类型转换汇总
  5. Domain Name System (DNS)
  6. javascript之变量、作用域、作用域链
  7. filter过滤器执行顺序
  8. Wikioi 1294 全排列
  9. android开机启动应用和服务
  10. SQL Server之LEFT JOIN、RIGHT LOIN、INNER JOIN的区别
  11. abp .net core area routes
  12. spark新闻项目环境搭建
  13. Pandas 练习题
  14. win10自带中文输入法的用户体验
  15. Android 应用开发实例之文件管理器
  16. Memory leak by misusing Autofac
  17. python之requests库使用问题汇总
  18. 20145109 《Java程序设计》第三周学习总结
  19. c#中获得MD5字符串方法
  20. java——static声明方法注意事项

热门文章

  1. Gearman任务分配
  2. DRF工程搭建
  3. BFS:HDU-1072-Nightmare
  4. Gym 100829S_surf 动态规划的优化
  5. linux下编译openjdk8
  6. python项目中输出指定颜色的日志
  7. TCP/IP网络编程之I/O流分离
  8. Asp.net自定义控件开发任我行(8)-数据集绑定
  9. 聊聊、Spring 数据源
  10. sqlserver2008透明书库加密