本文将详细介绍MMU段式转换的过程,并在文末附上一篇讲MMU比较详细的文章。具体什么是MMU,什么时段是转换就不在本文讲了,直接戳文末的链接。

  首先,进行段式转换的条件。我们要拥有一个虚拟地址,还有一级页表,这个一级页表一般是工程师在代码中建立起来的。每一个虚拟地址在这个一级页表中都有对应的表项。我们只需要知道一级页表的基地址,再将虚拟地址的高12位作为偏移,就可以找到该虚拟地址的表项了。从这里就可以看出,前12位相同的虚拟地址们在一级页表中其实都是共用同一个表项的。举个例子:0x56000000~0x560FFFFF这1MB的空间都是使用的同一个表项。

  其次,我们找到了这个表项,那他有什么卵用呢?我们先看看表项的格式,如下图:

  高12位为段的基地址,其他的位的意义参考《ARM920T_TRM1_S》的3.3.4小结,本文重点不在这里,故不再赘述。最重要的就是段的基地址,有了它,我们就能通过将它和虚拟地址的低20位进行拼接,从而得到我们外设需要的物理地址。这里也能看出来,一个段的大小有2^20也就是1MB这么大。

  整个过程简而言之就是:通过虚拟地址的高12位找到一级页表中对应的表项,取该表项的高12位再与虚拟地址的低20位进行拼接,就得到了物理地址,这样就完成了从虚拟地址到物理地址的转换。

  下面说说我在理解这些东西时候产生的误区,希望大家不要再犯:

  1、之前一直误认为表项里面存储的就是物理地址,其实不是这样的,物理地址是将表项的高12位和虚拟地址的低20位进行拼接得来的。表项的低20位还是有别的用处的,比如决定一些权限位,以及是否使用cache,write_buffer等。

  2、一级页表的基地址和段的基地址不是一回事,页表只是存储表项用的,表项记录了一些段的基地址。比如我们控制LED需要用0x56000010和0x56000014这两个地址处的寄存器,他们属于同一个段,段的基地址是0x56000000,而我们可能将页表存储在另外一个地方,比如0x30000000,所以这两个地址是毫无联系的。

  参考代码:

  

//1、建立一级页表,这里把它放在内存的起始地址,也就是页表的基地址

//2、将虚拟地址的高12位作为偏移,用来寻找该虚拟地址对应的表项

//3、表项的内容:高12位为段的基地址的高12位,低20位为下述定义的宏

//4、物理地址:由段的基地址和虚拟地址的低20位拼接而来

#define GPBCON *((volatile unsigned long*)0xA0000010)
#define GPBDAT *((volatile unsigned long*)0xA0000014) #define MMU_SECTION (2 << 0)
#define MMU_CACHE (1 << 3)
#define MMU_BUFFER (1 << 2)
#define MMU_SPECIAL (1 << 4)
#define MMU_FULL_ACCESS (3 << 10)
#define MMU_DOMAIN (0 << 5) #define SECDESC MMU_SECTION | MMU_SPECIAL | MMU_DOMAIN | MMU_FULL_ACCESS
#define SECDESC_WB MMU_SECTION | MMU_SPECIAL | MMU_DOMAIN | MMU_FULL_ACCESS | MMU_BUFFER | MMU_CACHE void create_page_table()
{
//将一级页表放在内存起始地址
unsigned long *ttb = (unsigned long*)0x30000000; unsigned long vaddr, paddr; //虚拟地址
vaddr = 0xA0000000;
//物理地址
paddr = 0x56000000; //表项的地址 = 一级页表基地址 + 虚拟地址高12位(作为索引)
*(ttb + (vaddr >> )) = (0x56000000 & 0xfff00000) | SECDESC; //表项的内容 vaddr = 0x30000000;
paddr = 0x30000000; while(vaddr < 0x34000000)
{
*(ttb + (vaddr >> )) = (paddr & 0xfff00000) | SECDESC_WB;
vaddr += 0x100000; //0x100000 = 16^5 = 2^20 = 1MB
paddr += 0x100000; }
} void mmu_init()
{
__asm__(
"ldr r0, =0x30000000\n"
"mcr p15, 0, r0, c2, c0, 0\n" "mvn r0, #0\n"
"mrc p15, 0, r0, c3, c0, 0\n" "mrc p15, 0, r0, c1, c0, 0\n"
"orr r0, r0, #0x0001\n"
"mcr p15, 0, r0, c1, c0, 0\n"
:
: );
} //使用虚拟地址GPBCON, GPBDAT点亮LED int gboot_main()
{ //1、建立一级页表
create_page_table();
//2、写入TTB,打开MMU
mmu_init(); GPBCON = 0x15400;
GPBDAT = 0b11010111111; return ;
}

  附加一篇讲MMU比较详细的文章(转):http://www.cnblogs.com/wrjvszq/p/4246634.html

  如有错误或问题,欢迎指出,转载请注明出处。

                                                          18:09:45

                                                            2015-07-26

  

对MMU段式转换的理解的更多相关文章

  1. ARM中MMU地址转换理解

    首先,我们要分清ARM CPU上的三个地址:虚拟地址(VA,Virtual Address).变换后的虚拟地址(MVA,Modified Virtual Address).物理地址(PA,Physic ...

  2. MMU段式映射(VA -> PA)过程分析

    MMU:内存管理单元. CPU寻址的方式: 未使用MMU:CPU发出地址(PA) 直接内存寻址(SDRAM or DDRx). 使用MMU  :CPU发出地址(VA) MMU接收CPU发来的地址 经过 ...

  3. java基础类型数据与String类包装类之间的转换与理解

    数据类型转换一般分为三种: 在java中整型,实型,字符型视为简单数据类型,这些数据类型由低到高分别为:(byte,short,char--int-long-float-double) 简单数据类型之 ...

  4. FFmpeg(四) 像素转换相关函数理解

    一.基本流程 1.sws_getCachedContext();//得到像素转换的上下文 2.sws_scale()://进行转换 二.函数说明 1.SwsContext *vctx = NULL;  ...

  5. JS 进制转换的理解

    该事情的由来是来自于一个面试题,题目是这样的,[1,2,3].map(parseInt)的结果是什么? 作为菜鸟的我们一定是觉得分别把1,2,3分别交给parseInt,无非就是1,2,3嘛.其实结果 ...

  6. 【读书笔记::深入理解linux内核】内存寻址【转】

    转自:http://www.cnblogs.com/likeyiyy/p/3837272.html 我对linux高端内存的错误理解都是从这篇文章得来的,这篇文章里讲的 物理地址 = 逻辑地址 – 0 ...

  7. 【读书笔记::深入理解linux内核】内存寻址

    我对linux高端内存的错误理解都是从这篇文章得来的,这篇文章里讲的 物理地址 = 逻辑地址 – 0xC0000000:这是内核地址空间的地址转换关系. 这句话瞬间让我惊呆了,根据我的CPU的知识,开 ...

  8. u-boot分析(十一)----MMU简单分析|u-boot分析大结局|学习规划

    u-boot分析(十一) 通过前面十篇博文,我们已经完成了对BL1阶段的分析,通过这些分析相信我们对u-boot已经有了一个比较深入的认识,在BL2阶段大部分是对外设的初始化,并且有的我们已经分析过, ...

  9. MMU功能解析、深入剖析、配置与使用

    MMU = memory management unit 1.把虚拟地址转化成物理地址,防止地址冲突 2.访问权限管理 MMU把一个虚拟地址的20位到31位作为取出来,建立 一张表,叫做transla ...

随机推荐

  1. Linux试玩指令开机关机

    Linux内核最初只是由芬兰人李纳斯·托瓦兹(Linus Torvalds)在赫尔辛基大学上学时出于个人爱好而编写的. Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和U ...

  2. Tomcat- java.lang.NoSuchMethodException: org.apache.catalina.deploy.WebXml addServlet

    在MyEclipse中启动Tomcat的时候报错: java.lang.NoSuchMethodException: org.apache.catalina.deploy.WebXml addServ ...

  3. Nginx和Apache共存环境下apache获得真实IP

    自从Nginx出现以后,我们都喜欢让 Nginx 跑在前方处理静态文件,然后通过 proxy 把动态请求过滤给 apache.这么有个问题,跑在后方 apache 上的应用获取到的IP都是Nginx所 ...

  4. What and where are the stack and heap?

    The stack is the memory set aside as scratch space for a thread of execution. When a function is cal ...

  5. ios 键盘弹起

    #pragma mark 键盘弹起操作 - (void)keyboardWillShow:(NSNotification *)notification{    NSDictionary *info = ...

  6. GCD介绍(三): Dispatch Sources

    何为Dispatch Sources         简单来说,dispatch source是一个监视某些类型事件的对象.当这些事件发生时,它自动将一个block放入一个dispatch queue ...

  7. Linux通配符

    * 任意字符 ?任意单个字符 [] 匹配指定 字符范围内的字符 [^] 指定范围之外的单个字符 常规字符集合 [a-z] a到z的所有小写字母 [A-Z] a到z的所有大写字母 [0-9] 0到9的所 ...

  8. Linux抓包工具tcpdump详解

    tcpdump是一个用于截取网络分组,并输出分组内容的工具,简单说就是数据包抓包工具.tcpdump凭借强大的功能和灵活的截取策略,使其成为Linux系统下用于网络分析和问题排查的首选工具. tcpd ...

  9. 【BZOJ1861】【splay】Book 书架

    Description 小 T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿 ...

  10. Bootstrap_Javascript_手风琴

    触发手风琴可以通过自定义的 data-toggle 属性来触发.其中data-toggle值设置为 collapse,data-target="#折叠区标识符". 第一步,设计一个 ...