如何用公司名称搜到公司网站,公司简介概况怎么写,苏州工业园区gdp,网站建设违约实验目的#xff1a;启用MMU#xff0c;映射SDRAM的地址空间#xff0c;操作虚拟地址实现“点灯大法”#xff0c;借此掌握MMU的使用。实验环境及说明#xff1a;恒颐S3C2410开发板H2410。H2410核心板扩展有64MB的K4S561632 SDRAM(4M*16bit*4BANK)#xff0c;地址范围是0…实验目的启用MMU映射SDRAM的地址空间操作虚拟地址实现“点灯大法”借此掌握MMU的使用。实验环境及说明恒颐S3C2410开发板H2410。H2410核心板扩展有64MB的K4S561632 SDRAM(4M*16bit*4BANK)地址范围是0x30000000~0x33FFFFFF。GPIO端口的地址范围是0x56000000~0X560000B0。实验思路开发板上电启动后自动将NandFlash开始的4K数据复制到SRAM中然后跳转到0地址开始执行然后初始化存储控制器SDRAM把2K后的代码从SRAM中复制到SDRAM中(存放在0x30004000前16KB用来存放页表)、设置页表、启动MMU实现虚拟地址映射GPIO寄存器和SDRAM最后跳转到SDRAM中(地址0xB0004000)运行。重新设置栈指针跳到点灯代码的入口点实现点灯操作。知识掌握MMU地址转换、内存访问权限检查、TLB及Cache的使用一、MMU地址转换 1.首先弄清除为什么要使用MMU纳MMU即内存管理单元直白一点的讲就像食堂的餐具所有的学生一起吃饭时不够用但食堂又不想再出资购买新的餐具(原因很明显一方面要成本另一方面又占地方。这就像增加内存一样)那么有没有解决办法根据以往经验得知不可能全学校的学习一起都到食堂吃饭于是食堂就找几个人负责餐具的管理(相当于MMU)他们一方面发放餐具保证来的同学有餐具可用另一方面又回收用完的餐具(这就相当于虚拟地址到物理地址之间建立了一个映射一样内存还是那么多但从任意单个程序角度都好像用不完一样)。当然如果有同学一个人拿好几套餐具肯定不允许的(这就相当于内存的权限检查)。MMU在地址转换过程中涉及到三种地址(VA---Virtual Address虚拟地址)---这个就相当于餐具存放的地方(大家都可以领到餐具)。CPU核心看到和用到的只是虚拟地址VA至于VA如果去对应物理地址PACPU核心不理会大家也不会去关心总共有多少餐具吧(MVA---Modified Virtual Address变换后的虚拟地址)---这个相当于放假的时候人很少只发餐具好了用过的就不先回收了节省人员了。Caches和MMU看不到VA他们利用MVA转换得到PA放假了回收餐具的人也不需要一直寻找用完的餐具(PA---Physical Address,物理地址)---实际的餐具量就那些。实际设备看不到VA、MVA读写它们使用的是物理地址PA同学们就餐一般会领到餐具。 2.虚拟地址到物理地址的转换过程。ARM使用页表来进行转换S3C2410最多会用到两级页表以段(Section1M)的方式进行转换时只用到一级页表以页(Page)的方式进行转换时用到两级页表。页的大小有3种大页(64KB)、小页(4KB)和极小页(1KB)。本文只是以段地址转换过程为例来讲解一下页的转换大同小异。 ★首先有个页表基址寄存器(位置为协处理器CP15的寄存器C2)它里面写入的就是一级页表的地址通过读取它就可以找到一级页表存放的起始位置。一级页表的地址是16K对齐(所以[13:0]为0使用[31:14]存储页表基址)。一级页表使用4096个描述符来表示4GB空间所以每个描述符对应1MB的虚拟地址存储它对应的1MB物理空间的起始地址或者存储下一级页表的地址。使用MVA[31:20]来索引一级页表(31-20一共12位2^124096所以是4096个描述符)得到一个描述符每个描述符占4个字节。 ★描述符最后两位为0B10时即是段的方式映射。[31:20]为段基址此描述符低20位填充0后就是一块1MB物理地址空间的起始地址。MVA[19:0]用来在这1MB空间中寻址。描述符的位[31:20]和MVA[19:0]构成了这个虚拟地址MVA对应的物理地址。以段的方式进行映射时虚拟地址MVA到物理地址PA的转换过程如下①页表基址寄存器位[31:14]和MVA[31:20]组成一个低两位为0的32位地址MMU利用这个地址找到段描述符②取出段描述符的位[31:20](段基址)它和MVA[19:0]组成一个32位的物理地址(这就是MVA对应的PA)。idiframe_0.04625395219773054 srcdata:text/html;charsetutf8,%3Cimg%20id%22img%22%20src%22http://www.arm79.com/attachment/Mon_1005/73_67_c19a93f3ccea9b3.jpg?_1758289%22%20style%22border:none;max-width:1505px%22%3E%3Cscript%3Ewindow.onload%20%20function%20()%20%7Bvar%20img%20%20document.getElementById(img);%20window.parent.postMessage(%7BiframeId:iframe_0.04625395219773054,width:img.width,height:img.height%7D,%20http://www.cnblogs.com);%7D%3C/script%3E frameborder0 scrollingno stylemargin: 0px; padding: 0px; border-style: none; border-width: initial; width: 20px; height: 20px;idiframe_0.06444169906899333 srcdata:text/html;charsetutf8,%3Cimg%20id%22img%22%20src%22http://www.arm79.com/attachment/Mon_1005/73_67_ba0dd29d824d17a.jpg?_1758289%22%20style%22border:none;max-width:1505px%22%3E%3Cscript%3Ewindow.onload%20%20function%20()%20%7Bvar%20img%20%20document.getElementById(img);%20window.parent.postMessage(%7BiframeId:iframe_0.06444169906899333,width:img.width,height:img.height%7D,%20http://www.cnblogs.com);%7D%3C/script%3E frameborder0 scrollingno stylemargin: 0px; padding: 0px; border-style: none; border-width: initial; width: 0px; height: 0px;二、内存的访问权限检查 内存的访问权限检查决定一块内存是否允许读/写。这由CP15寄存器C3(域访问控制)、描述符的域(Domain)、CP15寄存器C1的R/S/A位和描述符的AP位共同决定。“域”决定是否对某块内存进行权限检查AP决定如何对某块内容进行权限检查。S3C2440有16个域CP15寄存器C3中每两位对应一个域(一共32位)用来表示这个域是否进行权限检查。 每两位数据的含义00---无访问权限(任何访问都将导致Domain fault异常)01---客户模式(使用段描述符、页描述符进行权限检查)10---保留(保留目前相当于“无访问权限”)11---管理模式(不进行权限检查允许任何访问)。Domain占用4位用来表示内存属于0-15哪一个域。三、TLB和Cache 首先说两者都是利用程序访问的局部性原理通过设置高速、小容量的存储器来提高性能。 1.(TLB---Translation Lookaside Buffers转译查找缓存):由于从MVA到PA的转换需要访问多次内存大大降低了CPU的性能故提出TLB办法改进。当CPU发出一个虚拟地址时MMU首先访问TLB。如果TLB中含有能转换这个虚拟地址的描述符则直接利用此描述符进行地址转换和权限检查否则MMU访问页表找到描述符后再进行地址转换和权限检查并将这个描述符填入TLB中下次再使用这个虚拟地址时就直接使用TLB用的描述符。使用TLB需要保证TLB中的内容与页表一致在启动MMU之前页表中的内容发生变化后尤其要注意。一般的做法是在启动MMU之前使整个TLB无效改变页表时使所涉及的虚拟地址对应的TLB中条目无效。 2.(Cache高速缓存)为提高程序的运行速度在主存和CPU通用寄存器之间设置一个高速的、容量相对较小的存储器把正在执行的指令地址附近的一部分指令或数据从主存调入这个存储器供CPU在一段时间内使用。 ★写数据的两种方式①(Write Through写穿式)---任一CPU发出写信号送到Cache的同时也写入主存保证主存的数据同步更新。优点是操作简单但由于主存速度慢降低了系统的写速度并占用了总线的时间。②(Write Back回写式)---数据一般只写到Cache这样可能出现Cache中的数据得到更新而主存中的数据不变(数据陈旧)的情况。此时可在Cache中设一个标志地址及数据陈旧的信息只有当Cache中的数据被换出或强制进行”清空“操作时才将原更新的数据写入主存响应的单元中保证了Cache和主存中数据一致。 ★Cache有以下两个操作①(Clean清空)---把Cache或Write buffer中已经脏的(修改过但未写入主存)数据写入主存。②(Invalidate使无效)---使之不能再使用并不将脏的数据写入主存。 ★S2C2440内置了(ICaches指令Cache)、(DCaches数据Cache)和(Write buffer写缓存)操作时需要用到描述符中的C位(Ctt)和B位(Btt)。①(ICaches指令Cache)---系统刚上电或复位时ICaches中的内容是无效的并且ICaches功能关闭。往Icr位(CP15协处理器中寄存器1的第12位)写1可以启动ICaches写0停止ICaches。ICaches一般在MMU开启后使用此时描述符的C位用来表示一段内存是否可以被Cache。若Ctt1允许Cache否则不允许。如果MMU没有开启ICaches也可以被使用此时CPU读取指令时所涉及的内存都被当做允许Cache。ICaches关闭时CPU每次取指都要读取主存性能低所以通常尽早启动ICaches。ICaches开启后CPU每次取指时都会先在ICaches中查看是否能找到所用指令而不管Ctt是0还是1。如果找到成为Cache命中找不到称为Cache丢失ICaches被开启后CPU的取指有如下三种情况Cache命中且Ctt为1时从ICaches中取指返回CPUCache丢失且Ctt为1时CPU从主存中取指并且把指令缓存到Cache中Ctt为0时CPU从主存中取指。②(DCaches数据Cache)---与ICaches相似系统刚上电或复位时DCaches中的内容无效并且DCaches功能关闭Write buffer中的内容也是被废弃不用的。往Ccr位(CP15协处理器 中寄存器1的第二位)写1启动DCaches写0停止DCaches。Write buffer和DCaches紧密结合额米有专门的控制来开启和停止它。与ICaches不同DCaches功能必须在MMU开启之后才能被使用。DCaches被关闭时CPU每次都去内存取数据。DCaches被开启后CPU每次读写数据时都会先在DCaches中查看是否能找到所要的数据不管Ctt是0还是1找到了称为Cache命中找不到称为Cache丢失。 ★使用Cache时需要保证Cache、Write buffer的内容和主存内容一致保证下面两个原则①清空DCaches使主存数据得到更新。②使无效ICaches使CPU取指时重新读取主存。 在实际编写程序时要注意如下几点①开启MMU前使无效ICachesDCaches和Write buffer。②关闭MMU前清空ICaches、DCaches即将“脏”数据写到主存上。③如果代码有变使无效ICaches这样CPU取指时会从新读取主存。④使用DMA操作可以被Cache的内存时将内存的数据发送出去时要清空Cache将内存的数据读入时要使无效Cache。⑤改变页表中地址映射关系时也要慎重考虑。⑥开启ICaches或DCaches时要考虑ICaches或DCaches中的内容是否与主存保持一致。⑦对于I/O地址空间不使用Cache和Write buffer。四、MMU、TLB及Cache的控制指令 S3C2410除了ARM920T的CPU核心外还有若干个协处理器用来帮助主CPU完成一些特殊功能对MMU、TLB及Cache等的操作就涉及到协处理器。格式如下 MCR|MRC{条件} 协处理器编码协处理器操作码1目的寄存器源寄存器1源寄存器2协处理器操作码2 MCR|MRC {cond} p#,expression1,Rd,cn,cm{,expression2} MRC //从协处理器获得数据传给ARM920T CPU核心寄存器 MCR //数据从ARM920T CPU核心寄存器传给协处理器 {cond} //执行条件省略时表示无条件执行 p# //协处理器序号 expression1 //一个常数 Rd //ARM920T CPU核心的寄存器 cn和cm //协处理器中的寄存器 expression2 //一个常数 其中expression1、cn、cm、expression2仅供协处理器使用它们的作用如何取决于具体的协处理器。示例代码解析 开启MMU并将虚拟地址0xA0000000~0xA0100000映射到物理地址0x56000000~0x56100000(GPFCON物理地址为0x56000050GPFDAT物理地址为0x56000054)将虚拟地址0xB0000000~0xB3FFFFFF映射到物理地址0x30000000~0x33FFFFFF。本示例以段的方式进行地址映射只使用一级页表通过上面内容可知一级页表使用4096个描述符来表示4G空间(每个描述符对应1MB)每个描述符占4字节所以一级页表占16KB。使用SDRAM的开始16KB存放一级页表所以剩下的内存开始地址就为0x30004000这个地址最终会对应虚拟地址0xB0004000(所以代码运行地址为0xB0004000)。★程序执行主要流程的示例代码。 .text .global _start _start: bl disable_watch_dog 关闭WATCHDOG否则CPU会不断重启 bl mem_control_setup 设置存储控制器以使用SDRAM ldr sp, 4096 设置栈指针以下是C函数调用前需要设好栈 bl copy_2th_to_sdram 将第二部分代码复制到SDRAM bl create_page_table 设置页表 bl mmu_init 启动MMU启动以后下面代码都用虚拟地址 ldr sp, 0xB4000000 重设栈指针指向SDRAM顶端(使用虚拟地址) ldr pc, 0xB0004000 跳到SDRAM中继续执行第二部分代码 halt_loop: b halt_loop★设置页表。 void create_page_table(void) { /* * 用于段描述符的一些宏定义[31:20]段基址[11:10]AP[8:5]Domain[3]C[2]B[1:0]0b10为段描述符 */ #define MMU_FULL_ACCESS (3 10) /* 访问权限AP */ #define MMU_DOMAIN (0 5) /* 属于哪个域 Domain*/ #define MMU_SPECIAL (1 4) /* 必须是1 */ #define MMU_CACHEABLE (1 3) /* cacheable C位*/ #define MMU_BUFFERABLE (1 2) /* bufferable B位*/ #define MMU_SECTION (2) /* 表示这是段描述符 */ #define MMU_SECDESC (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | MMU_SECTION) #define MMU_SECDESC_WB (MMU_FULL_ACCESS | MMU_DOMAIN | MMU_SPECIAL | MMU_CACHEABLE | MMU_BUFFERABLE | MMU_SECTION) #define MMU_SECTION_SIZE 0x00100000 /*每个段描述符对应1MB大小空间*/ unsigned long virtuladdr, physicaladdr; unsigned long *mmu_tlb_base (unsigned long *)0x30000000; /*SDRAM开始地址存放页表*/ /* * Steppingstone的起始物理地址为0第一部分程序的起始运行地址也是0 为了在开启MMU后仍能运行第一部分的程序 将01M的虚拟地址映射到同样的物理地址 */ virtuladdr 0; physicaladdr 0; /*虚拟地址[31:20]用于索引一级页表找到它对应的描述符对应于(virtualaddr20)。段描述符中[31:20]保存段的物理地址对应(physicaladdr 0xFFF00000)*/ *(mmu_tlb_base (virtuladdr 20)) (physicaladdr 0xFFF00000) | MMU_SECDESC_WB; /* * 0x56000000是GPIO寄存器的起始物理地址GPBCON和GPBDAT这两个寄存器的物理地址0x56000010、0x56000014 为了在第二部分程序中能以地址0xA0000010、0xA0000014来操作GPBCON、GPBDAT * 把从0xA0000000开始的1M虚拟地址空间映射到从0x56000000开始的1M物理地址空间 */ virtuladdr 0xA0000000; physicaladdr 0x56000000; *(mmu_tlb_base (virtuladdr 20)) (physicaladdr 0xFFF00000) | MMU_SECDESC; /* * SDRAM的物理地址范围是0x300000000x33FFFFFF 将虚拟地址0xB00000000xB3FFFFFF映射到物理地址0x300000000x33FFFFFF上 总共64M涉及64个段描述符 */ virtuladdr 0xB0000000; physicaladdr 0x30000000; while (virtuladdr 0xB4000000) { *(mmu_tlb_base (virtuladdr 20)) (physicaladdr 0xFFF00000) | MMU_SECDESC_WB; virtuladdr MMU_SECTION_SIZE; physicaladdr MMU_SECTION_SIZE; } }★ 启动MMU。 void mmu_init(void) { unsigned long ttb 0x30000000; __asm__( mov r0, #0\n mcr p15, 0, r0, c7, c7, 0\n /* 使无效ICaches和DCaches */ mcr p15, 0, r0, c7, c10, 4\n /* drain write buffer on v4 */ mcr p15, 0, r0, c8, c7, 0\n /* 使无效指令、数据TLB */ mov r4, %0\n /* r4 页表基址 */ mcr p15, 0, r4, c2, c0, 0\n /* 设置页表基址寄存器 */ mvn r0, #0\n mcr p15, 0, r0, c3, c0, 0\n /* 域访问控制寄存器设为0xFFFFFFFF 不进行权限检查*/ /* * 对于控制寄存器先读出其值在这基础上修改感兴趣的位然后再写入 */ mrc p15, 0, r0, c1, c0, 0\n /* 读出控制寄存器的值 */ /* 控制寄存器的低16位含义为.RVI ..RS B... .CAM * R : 表示换出Cache中的条目时使用的算法0 Random replacement1 Round robin replacement * V : 表示异常向量表所在的位置0 Low addresses 0x000000001 High addresses 0xFFFF0000 * I : 0 关闭ICaches1 开启ICaches * R、S : 用来与页表中的描述符一起确定内存的访问权限 * B : 0 CPU为小字节序1 CPU为大字节序 * C : 0 关闭DCaches1 开启DCaches * A : 0 数据访问时不进行地址对齐检查1 数据访问时进行地址对齐检查 * M : 0 关闭MMU1 开启MMU */ /* * 先清除不需要的位往下若需要则重新设置它们 */ /* .RVI ..RS B... .CAM */ bic r0, r0, #0x3000\n /* ..11 .... .... .... 清除V、I位 */ bic r0, r0, #0x0300\n /* .... ..11 .... .... 清除R、S位 */ bic r0, r0, #0x0087\n /* .... .... 1... .111 清除B/C/A/M */ /* * 设置需要的位 */ orr r0, r0, #0x0002\n /* .... .... .... ..1. 开启对齐检查 */ orr r0, r0, #0x0004\n /* .... .... .... .1.. 开启DCaches */ orr r0, r0, #0x1000\n /* ...1 .... .... .... 开启ICaches */ orr r0, r0, #0x0001\n /* .... .... .... ...1 使能MMU */ mcr p15, 0, r0, c1, c0, 0\n /* 将修改的值写入控制寄存器 */ : /* 无输出 */ : r (ttb) ); }