(1)、MMU介绍
a、权限管理
不同地址空间的程序是无法相互访问的,否则会发生错误。
b、地址映射
老师在视频中关于MMU讲解不是很多,要求也只是了解MMU这个概念就行了,可以参考书上或者下面这个文章了解MMU
http://www.cnblogs.com/bigbear1385/p/5325344.html
1、 建立表格,就是建立虚拟地址到物理地址的映射
2、 把表格地址告诉MMU
3、 启动MMU
(2)、程序代码
首先我们看汇编代码,因为我们的主要程序都在汇编代码里面了。
.text .global _start _start: ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈 bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启 bl memsetup @ 设置存储控制器以使用SDRAM bl copy_2th_to_sdram @ 将第二部分代码复制到SDRAM bl create_page_table @ 设置页表 bl mmu_init @ 启动MMU ldr sp, =0xB4000000 @ 重设栈指针,指向SDRAM顶端(使用虚拟地址) ldr pc, =0xB0004000 @ 跳到SDRAM中继续执行第二部分代码 @ ldr pc, =main halt_loop: b halt_loop
ldr sp, =4096
bl disable_watch_dog
bl memsetup
这三句代码和前几集课的功能是一样的,设置栈、关看门狗、初始化SDRAM。
接下来是拷贝代码到SDRAM里面去,这个代码和之前不太一样,需要涉及到连接脚本的内容。
1 firtst 0x00000000 : { head.o init.o } 2 3 second 0xB0004000 : AT(2048) { leds.o }
首先第一段代码是从0x00000000开始的执行的没问题,但是我们的主函数的代码的地址是被放在了2048,并重定位地址为0xB0004000(这个是虚拟地址,在后面需要把它映射到一个物理地址上去)。
1 void copy_2th_to_sdram(void) 2 { 3 unsigned int *pdwSrc = (unsigned int *)2048; 4 unsigned int *pdwDest = (unsigned int *)0x30004000; 5 6 while (pdwSrc < (unsigned int *)4096) 7 { 8 *pdwDest = *pdwSrc; 9 pdwDest++; 10 pdwSrc++; 11 } 12 }
这段代码是拷贝第二段代码到SDRAM里面去,因为第二段代码是从个2048开始的,并且我们的内部RAM只有4096,所以我们把从2048到4096的代码全部拷贝到0x30004000处。并留出0x30000000~0x30004000的地址空间用来存放一级页表的设置内容,一级页表的基地址就是0x30000000。
设置页表:
1 virtuladdr = 0; 2 physicaladdr = 0; 3 *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | 4 MMU_SECDESC_WB;
这几句代码是把物理地址起始位置为0的1M地址空间映射到虚拟地址的起始地址位0的1M地址空间去。
目的是为了在开启MMU后仍然能够运行第一段代码。
为什么是1M:因为我们采用的是段描述的页表。
1 virtuladdr = 0xA0000000; 2 physicaladdr = 0x56000000; 3 *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | 4 MMU_SECDESC;
这几句代码是把GPIO的起始物理地址为0x56000000的1M地址空间映射到虚拟地址0xA0000000,记住,后面要使用到。
1 virtuladdr = 0xB0000000; 2 physicaladdr = 0x30000000; 3 while (virtuladdr < 0xB4000000) 4 { 5 *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | 6 MMU_SECDESC_WB; 7 virtuladdr += 0x100000; 8 physicaladdr += 0x100000; 9 }
这里是完全把SDRAM的64M的地址空间完全映射到起始地址为0xB0000000虚拟地址空间里去。
设置完页表后,接着启动MMU,重设栈指针到SDRAM的顶端。最后跳到0xB0004000里去执行第二段代码。
不知道是没完全弄懂,还是怎么回事?这节课听的迷迷糊糊的。嘛,以后进入linux后再结合相关内容深入研究一下。