|
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代码实践:
- /*********************************************************************************/
- /**************************************宏定义*************************************/
- /*********************************************************************************/
- #define MMU_BASE 0x4000c000 // 页表基址
- #define MMU_FULL_ACCESS (3 << 10) // 访问权限
- #define MMU_DOMAIN (0 << 5) // 属于哪个域
- #define MMU_SPECIAL (1 << 4) // bit 4必须是1
- #define MMU_CACHEABLE (1 << 3) // 可以使用cache
- #define MMU_BUFFERABLE (1 << 2) // 可以使用write buffer
- #define MMU_SECDESC (2) // 表示这是段描述符
- /********************************允许Cache&Buffer*********************************/
- #define MMU_SECDESC_WB (MMU_FULL_ACCESS | MMU_DOMAIN | \
- MMU_SPECIAL | MMU_CACHEABLE | \
- MMU_SECDESC)
-
- /********************************禁用Cache&Buffer*********************************/
- #define MMU_SECDESC_NCNB (MMU_FULL_ACCESS | MMU_DOMAIN | \
- MMU_SPECIAL | MMU_SECDESC)
-
- /*********************************************************************************/
- /***********************************配置并启动MMU*********************************/
- /*********************************************************************************/
- void mmu_init(void)
- {
- /*******************************新建立页表项**********************************/
- volatile unsigned long *table = (volatile unsigned long *)MMU_BASE;
- /* VA: 0x00000000 => PA: 0x40000000 允许Cache%Buffer */
- table[0x000] = 0x40000000 | MMU_SECDESC_WB;
- /* VA: 0x40000000 => PA: 0x40000000 允许Cache%Buffer */
- table[0x400] = 0x40000000 | MMU_SECDESC_WB;
- /* VA: 0x56000000 => PA: 0x56000000 禁止Cache%Buffer */
- /* 这一块地址是用来操作GPB寄存器的 直接访问物理地址 */
- table[0x560] = 0x56000000 | MMU_SECDESC_NCNB;
- /*********************************启用MMU*************************************/
- __asm__ (
- "mov r1, #0\n"
- "mcr p15, 0, r1, c7, c7, 0\n" // invalidate ICaches & DCaches
- "mcr p15, 0, r1, c7, c10, 4\n" // drain write buffer on v4
- "mcr p15, 0, r1, c8, c7, 0\n" // invalidate Data & Instruction TLB
- "mcr p15, 0, %0, c2, c0, 0\n" // write TTB register
- "mrc p15, 0, r1, c3, c0, 0\n" // read domain 15:0 access permissions
- "orr r1, r1, #3\n" // domain 0, Accesses are not checked
- "mcr p15, 0, r1, c3, c0, 0\n" // write domain 15:0 access permissions
- "mrc p15, 0, r1, c1, c0, 0\n" // Read control register
- "orr r1, r1, #(1<<2)\n" // Data cache enable
- "orr r1, r1, #(1<<12)\n" // Instruction cache enable
- "orr r1, r1, #(1<<14)\n" // Round robin replacement
-
- "orr r1, r1, #(1<<0)\n" // MMU enable
- "mcr p15,0,r1,c1, c0,0\n" // write control register
- :
- : "r" (table)
- : "r1"
- );
- }
复制代码
注意:MMU已经开启,CPU所有对地址的处理都会经过MMU,不过好在table[0x400] = 0x40000000 | MMU_SECDESC_WB;就不要担心会出什么问题了。
这样就只要在发生异常之前调用mmu_init这个函数,就可以使用物理地址0x4000000处的异常向量表了
下面我们使用“swi”指令来试验是否能够成功跳转到预定的指令,为了看到实验结果,我们在swi异常中点亮LED灯。
代码如下:
- @******************************************************************************
- @ File:start.S
- @ 功能:测试地址重映射是否成功
- @******************************************************************************
- .text
- .global _start
- _start:
- @************ 异常向量表 *************@
- B Reset_Handler
- B Handler_LOOP
- B SWI_Handler
- B Handler_LOOP
- B Handler_LOOP
- B Handler_LOOP
- B Handler_LOOP
- B Handler_LOOP
-
- Reset_Handler:
- @关闭看门狗
- LDR R0, =0x53000000
- LDR R1, [R0]
- BIC R1, R1, #0x01
- STR R1, [R0]
-
- @设置栈
- LDR SP, =0x40010000
-
- @调用mmu初始化函数
- BL mmu_init
-
- @发出SWI异常
- swi
-
- MAIN_LOOP:
- B MAIN_LOOP
-
- @************ SWI_Handler *************@
- SWI_Handler:
- @点亮LED,仅测试是否成功跳转,就不保存现场了
- LDR R0, =0x56000010
- MOV R1, #0x00000004
- STR R1, [R0]
-
- LDR R0, =0x56000014
- MOV R1, #0x00000000
- STR R1, [R0]
-
- Handler_LOOP:
- B Handler_LOOP
-
-
- .end
-
复制代码 实验结果:
LED成功点亮,说明地址重映射成功。
源码:
mmu_test.rar
(3.32 KB, 下载次数: 9)
论坛ID: yuanlai2010
发表时间:2014-07-23
|
|