对MMU段式转换的理解

  本文将详细介绍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 >> 20)) = (0x56000000 & 0xfff00000) | SECDESC;        //表项的内容

    vaddr = 0x30000000;
    paddr = 0x30000000;

    while(vaddr < 0x34000000)
    {
        *(ttb + (vaddr >> 20)) = (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 0;
}

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

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

                                                          18:09:45

                                                            2015-07-26

  

时间: 2024-10-06 12:46:48

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

个人对TCP11种状态转换的理解

首先就是这张很经典的图,我们围绕这个图开讲 咱分条来说各个转换之间的动作 首先从CLOSED开始 如果是CLOSED->LISTEN 代表这是服务端 监听某个端口 准备接受其他人的connect了 如果是CLOSED->SYN_SENT 代表这是一个客户端发送了connect  发送了SYN=1,进行了TCP的第一次握手 然后等待对方的第二次握手发送SYN=1和ACK=1 当收到了SYN=1和ACK=1后(第二次握手),并且自己发送了ACK=1(第三次握手) 这时候在客户端这边,就已经建立了T

ARM中MMU地址转换理解

首先,我们要分清ARM CPU上的三个地址:虚拟地址(VA,Virtual Address).变换后的虚拟地址(MVA,Modified Virtual Address).物理地址(PA,Physical Address) 启动MMU后,CPU核对外发出虚拟地址VA,VA被转换为MVA供MMU使用,在这里MVA被转换为PA:最后通过PA读写实际设备 MMU的作用就是负责虚拟地址(virtual address)转化成物理地址(physical address). 32位的CPU的虚拟地址空间达到

任意进制转换简单理解

规则1:任意进制转10进制都是当前位数乘以当前位权重 规则2:N进制转M进制根据前值除/M的值,然后取M进制余数为当前位,小数位就是后乘取整;(基本就是这个思想) 首先,实现任意进制转其他进制,最好先转到10进制在操作比较方便; 目前代码只实现10->36 思想是一样的使用递归计算- -改变除数(/N)和求的余数(/M),然后根据逻辑值对应字符表示就是- -,楼主目前不知道Z以上怎么表示- -所以懵 1 #include <iostream> 2 3 4 void turnto36(in

CSS3中3D转换的理解

translateZ(z):表示相对于屏幕的前后位置.值越大元素离屏幕越近,值越小离的远.必须开启3D模式和设置3D透视效果才有作用. transform-style perspective

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

u-boot分析(十一) 通过前面十篇博文,我们已经完成了对BL1阶段的分析,通过这些分析相信我们对u-boot已经有了一个比较深入的认识,在BL2阶段大部分是对外设的初始化,并且有的我们已经分析过,在这篇博文我打算对BL1阶段没有分析到的重要外设进行简单分析,并结束对u-boot的分析,同时对后面自己的博文进行简单的规划,希望有兴趣的朋友跟我一块学习和研究嵌入式. 今天我们会分析到以下内容: 1.      MMU分析(内容出自我以前的博客) 2.      裸机开发总结 3.      后期

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

我对linux高端内存的错误理解都是从这篇文章得来的,这篇文章里讲的 物理地址 = 逻辑地址 – 0xC0000000:这是内核地址空间的地址转换关系. 这句话瞬间让我惊呆了,根据我的CPU的知识,开启分页之后,任何寻址都要经过mmu的转换,也就是一个二级查表的过程(386) 难道内核很特殊,当mmu看到某个逻辑地址是内核传来的之后,就不查表了,直接减去0xC0000000,然后就传递给内存控制器了??? 我发现网上也有人和我问了同样的问题,看这个问题 这句话太让人费解了,让人费解到以至于要怀疑

理解restful API

简介 随着Web开发的不断开发, 低耦合的需求被提上了日程, 催生出了前后端分离的方案. 前后端分离使前端和服务器端相互独立, 细化前后端开发, 于是近几年API架构风行. RESTful架构由Roy Fielding在一篇博士论文中提出. `REST, 即Representational State Transfer的缩写, 中文可以译为表现层状态转化 表现层可以理解为资源的表现层, 资源在网络通信中无处不在, 一段文本, 一张图片, 一个文档都是资源, JSON是现在最常用的资源表示格式.

第二十一篇 Java 数据类型的定义 ,以及基础类型的自动转换和强制转换

大家好,今天呢我吧我所学到的一些知识点共享给大家,希望大家看完之后,要是有什么不懂的,请随时联系我,要是觉得我写的不是很好的 ,还希望你们能够谅解一下,因为小弟我刚学会写博客也没多久,很多格式和方法都不是很完善,希望大家多多包涵,好了 废话就不多说了,来谈一下今天我所学到的一些知识点吧: 今天我主要是学到了一些Java中的数据类型,其中,Java中的数据类型分为俩类------基础数据类和逻辑数据类,下面我所介绍的都是基本数据类的一些分类,至于逻辑类,由于使用次数过少,所以今天就不再这里多做介绍

Myeclipse - Web项目转换技巧--处理Java项目、SVN非Web项目问题

喜欢从业的专注,七分学习的态度. 概述 对于Java调试,使用Eclipse习惯性的使用Junit调试,使用Myeclipse习惯性的将项目转成Web项目在Tomcat或Weblogic中调试,在Myeclipse项目对项目Web属性的理解有助于应对开发环境的配置.发布和部署,涉及的技巧和操作比较多.最常用最简单的技巧是将Java项目转Web项目技巧. 环境准备:创建一个Java项目 打开Myeclipse--右键--选择Project 创建1 点击Next(下一步) 创建-项目 点击Finis