3758|4

241

帖子

4

TA的资源

纯净的硅(初级)

楼主
 

Helper2416-18——裸机第九弹——MMU&异常处理实践+实践源码 [复制链接]

本帖最后由 yuanlai2010 于 2014-7-23 20:52 编辑

裸机第九弹——MMU&异常处理实践

参与Helper2416开发板助学计划心得


MMU简介:

MMU是Memory Management Unit的缩写,中文名是内存管理单元,它是中央处理器(CPU)中用来管理虚拟存储器、物理存储器的控制线路,同时也负责虚拟地址映射为物理地址,以及提供硬件机制的内存访问授权。


关于虚拟地址与物理地址:

1:什么是虚拟地址?

   虚拟地址:4GB虚拟地址空间中的地址,程序中使用的都是虚拟地址。在MMU开启之前虚拟地址=物理地址

2:什么是物理地址?
   物理地址:出现在CPU地址总线上的地址。


MMU主要功能及应用目的:
1:将线性地址映射为物理地址
这个对于我来说,主要就是要把虚拟地址0x00开始的这一块地址映射到我能访问的实际物理地址上来,比如0x40000000开始的IROM或者是0x30000000开始的DRAM,这样我就能使用自己的异常向量表了,才能继续下一步中断的实践(比如UART、TIMER。。。都需要中断功能)

2:提供硬件机制的内存访问授权
其实对于裸机程序来说,权限管理暂时还没有什么用处,玩系统的时候再来实践。

MMU的详细介绍和使用方法:这个东西以我的实力恐怕是难以写出一份详尽的教程出来,我就不在这里献丑了。
这里推荐韦东山老师的这本《嵌入式Linux应用开发完全手册》,其中第七章详细的讲解了MMU原理及使用方法,同时还有很多容易犯错的地方都指出来了,一些错误都是前些日子写boot的时候犯过的,看了这个之后感觉真是受益良多啊
由于附件大小限制在15MB以内,我会在楼下贴出下载链接,由于要通过审核,可能会慢一些。

目标:
使用一级页表,把虚拟地址0x00000000开始的1MB地址空间映射到IROM起始地址0x40000000开始的1MB实际地址空间。同时把虚拟地址0x40000000也映射实际地址0x40000000的位置。同时开启Cache加快指令执行速度。
这样就可以把我们的异常向量表放在我们的启动代码中了,同时又不因我们的链接地址是0x40000000而非得使用位置无关码编写代码了


MMU代码实践:
  1. /*********************************************************************************/
  2. /**************************************宏定义*************************************/
  3. /*********************************************************************************/

  4. #define MMU_BASE                            0x4000c000        // 页表基址
  5. #define MMU_FULL_ACCESS       (3 << 10)          // 访问权限
  6. #define MMU_DOMAIN            (0 << 5)           // 属于哪个域
  7. #define MMU_SPECIAL           (1 << 4)           // bit 4必须是1
  8. #define MMU_CACHEABLE         (1 << 3)           // 可以使用cache
  9. #define MMU_BUFFERABLE        (1 << 2)           // 可以使用write buffer
  10. #define MMU_SECDESC           (2)                // 表示这是段描述符

  11. /********************************允许Cache&Buffer*********************************/
  12. #define MMU_SECDESC_WB        (MMU_FULL_ACCESS | MMU_DOMAIN | \
  13.                                   MMU_SPECIAL | MMU_CACHEABLE | \
  14.                                   MMU_SECDESC)
  15.                                                          
  16. /********************************禁用Cache&Buffer*********************************/                                                         
  17. #define MMU_SECDESC_NCNB      (MMU_FULL_ACCESS | MMU_DOMAIN | \
  18.                                   MMU_SPECIAL | MMU_SECDESC)
  19.                                                          
  20. /*********************************************************************************/
  21. /***********************************配置并启动MMU*********************************/
  22. /*********************************************************************************/
  23. void mmu_init(void)
  24. {
  25.         /*******************************新建立页表项**********************************/
  26.         volatile unsigned long *table = (volatile unsigned long *)MMU_BASE;

  27.         /*  VA: 0x00000000 => PA: 0x40000000  允许Cache%Buffer */
  28.         table[0x000] = 0x40000000 | MMU_SECDESC_WB;        
  29.         /*  VA: 0x40000000 => PA: 0x40000000  允许Cache%Buffer */
  30.         table[0x400] = 0x40000000 | MMU_SECDESC_WB;
  31.         /*  VA: 0x56000000 => PA: 0x56000000  禁止Cache%Buffer */
  32.         /*  这一块地址是用来操作GPB寄存器的   直接访问物理地址 */
  33.         table[0x560] = 0x56000000 | MMU_SECDESC_NCNB;

  34.         /*********************************启用MMU*************************************/
  35.         __asm__ (

  36.                 "mov    r1, #0\n"
  37.                 "mcr    p15, 0, r1, c7, c7, 0\n"    // invalidate ICaches & DCaches

  38.                 "mcr    p15, 0, r1, c7, c10, 4\n"   // drain write buffer on v4
  39.                 "mcr    p15, 0, r1, c8, c7, 0\n"    // invalidate Data & Instruction TLB

  40.                 "mcr p15, 0, %0, c2, c0, 0\n"                 // write TTB register
  41.                 "mrc p15, 0, r1, c3, c0, 0\n"                 // read domain 15:0 access permissions
  42.                 "orr r1, r1, #3\n"                            // domain 0, Accesses are not checked
  43.                 "mcr p15, 0, r1, c3, c0, 0\n"                 // write domain 15:0 access permissions

  44.                 "mrc p15, 0, r1, c1, c0, 0\n"                 // Read control register

  45.                 "orr r1, r1, #(1<<2)\n"                       // Data cache enable
  46.                 "orr r1, r1, #(1<<12)\n"                      // Instruction cache enable
  47.                 "orr r1, r1, #(1<<14)\n"                      // Round robin replacement
  48.                
  49.                 "orr r1, r1, #(1<<0)\n"                       // MMU enable

  50.                 "mcr p15,0,r1,c1, c0,0\n"                     // write control register
  51.                 :
  52.                 : "r" (table)
  53.                 : "r1"
  54.         );
  55. }
复制代码


注意:MMU已经开启,CPU所有对地址的处理都会经过MMU,不过好在table[0x400] = 0x40000000 | MMU_SECDESC_WB;就不要担心会出什么问题了。

这样就只要在发生异常之前调用mmu_init这个函数,就可以使用物理地址0x4000000处的异常向量表了

下面我们使用“swi”指令来试验是否能够成功跳转到预定的指令,为了看到实验结果,我们在swi异常中点亮LED灯。
代码如下:
  1. @******************************************************************************
  2. @ File:start.S
  3. @ 功能:测试地址重映射是否成功
  4. @******************************************************************************   
  5. .text
  6. .global _start
  7. _start:
  8. @************   异常向量表   *************@
  9.                 B        Reset_Handler
  10.                 B        Handler_LOOP
  11.                 B        SWI_Handler
  12.                 B        Handler_LOOP
  13.                 B        Handler_LOOP
  14.                 B        Handler_LOOP
  15.                 B        Handler_LOOP
  16.                 B        Handler_LOOP
  17.                
  18. Reset_Handler:               
  19.                 @关闭看门狗
  20.                 LDR        R0,        =0x53000000
  21.                 LDR        R1,         [R0]
  22.                 BIC        R1,        R1,        #0x01
  23.                 STR        R1,        [R0]
  24.                
  25.                 @设置栈
  26.                 LDR        SP,        =0x40010000
  27.                
  28.                 @调用mmu初始化函数
  29.                 BL        mmu_init
  30.                
  31.                 @发出SWI异常
  32.                 swi
  33.                         
  34. MAIN_LOOP:
  35.                 B       MAIN_LOOP
  36.                
  37. @************   SWI_Handler   *************@
  38. SWI_Handler:
  39.                 @点亮LED,仅测试是否成功跳转,就不保存现场了
  40.                 LDR        R0,        =0x56000010
  41.                 MOV        R1,        #0x00000004        
  42.                 STR        R1,        [R0]
  43.             
  44.                 LDR        R0,        =0x56000014
  45.                 MOV        R1,        #0x00000000
  46.                 STR        R1,        [R0]
  47.                
  48. Handler_LOOP:
  49.                 B       Handler_LOOP
  50.                
  51.                         
  52. .end
  53.                         
复制代码
实验结果:
LED成功点亮,说明地址重映射成功。

源码: mmu_test.rar (3.32 KB, 下载次数: 9)


论坛ID: yuanlai2010

发表时间:2014-07-23











最新回复

不错 顶一个,书上我看了几遍,一直没有整明白   详情 回复 发表于 2014-8-10 16:09
点赞 关注

回复
举报

554

帖子

0

TA的资源

版主

沙发
 
没事,可以编辑的!
 
 

回复

241

帖子

4

TA的资源

纯净的硅(初级)

板凳
 
在这里附上《嵌入式Linux应用开发完全手册》高清扫描件,很好的一本教材
链接已隐藏,如需查看请登录或者注册
 
 
 

回复

241

帖子

4

TA的资源

纯净的硅(初级)

4
 
昨天晚上编辑了一点,就失误的点击了发表,简直就是悲剧啊,所以设置了访问权限,今晚用时间写完了帖子,现在重新开放权限。
 
 
 

回复

33

帖子

0

TA的资源

一粒金砂(中级)

5
 
不错 顶一个,书上我看了几遍,一直没有整明白
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表