首页 > 代码库 > 跟着韦老师学Linux学习笔记(三)-MMU

跟着韦老师学Linux学习笔记(三)-MMU

(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  = http://www.mamicode.com/(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后再结合相关内容深入研究一下。

 

 

跟着韦老师学Linux学习笔记(三)-MMU