首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 嵌入开发 > WinCE >

2008年最后一帖——了结MMU和cache(顺便纠正以前的异常)

2012-03-11 
2008年最后一帖——了结MMU和cache(顺便纠正以前的错误)这两天,重新看了MMU和cache,对它有了一点了解,现在再

2008年最后一帖——了结MMU和cache(顺便纠正以前的错误)
这两天,重新看了MMU和cache,对它有了一点了解,现在再把疑问放到论坛上来,希望大家帮忙(前几天参与押宝,现在分数还没有回来,没有分发帖了,以后有分再补回吧,sorry)
——————————————————————————————————————
我看了的ADS bootloader部分,发现一个很奇怪的问题,它居然只是对一级页表做了配置,并且把虚拟内存和物理内存映射成相等
不知道为什么会这样。这不是多此一举吗?
看如下代码(三星提供)

C/C++ code
/************************************************   NAME    : MMU.C  DESC      :  Revision: 2002.2.28 ver 0.0 ************************************************/#include "def.h"#include "option.h"#include "2440addr.h"#include "2440lib.h"#include "2440slib.h"#include "mmu.h"// 1) Only the section table is used. // 2) The cachable/non-cachable area can be changed by MMT_DEFAULT value.//    The section size is 1MB. void MMU_Init(void){    int i,j;    //========================== IMPORTANT NOTE =========================    //The current stack and code area can't be re-mapped in this routine.    //If you want memory map mapped freely, your own sophiscated MMU    //initialization code is needed.    //===================================================================    MMU_DisableDCache();    MMU_DisableICache();    //If write-back is used,the DCache should be cleared.    for(i=0;i<64;i++)        for(j=0;j<8;j++)            MMU_CleanInvalidateDCacheIndex((i<<26)|(j<<5));    MMU_InvalidateICache();        #if 0    //To complete MMU_Init() fast, Icache may be turned on here.    MMU_EnableICache();     #endif        MMU_DisableMMU();    MMU_InvalidateTLB();    //MMU_SetMTT(int vaddrStart,int vaddrEnd,int paddrStart,int attr)    MMU_SetMTT(0x00000000,0x07f00000,0x00000000,RW_CNB);  //bank0    MMU_SetMTT(0x08000000,0x0ff00000,0x08000000,RW_CNB);  //bank1    MMU_SetMTT(0x10000000,0x17f00000,0x10000000,RW_NCNB); //bank2    MMU_SetMTT(0x18000000,0x1ff00000,0x18000000,RW_NCNB); //bank3    //MMU_SetMTT(0x20000000,0x27f00000,0x20000000,RW_CB); //bank4    MMU_SetMTT(0x20000000,0x27f00000,0x20000000,RW_CNB); //bank4 for STRATA Flash    MMU_SetMTT(0x28000000,0x2ff00000,0x28000000,RW_NCNB); //bank5    MMU_SetMTT(0x30000000,0x30f00000,0x30000000,RW_CB);      //bank6-1    MMU_SetMTT(0x31000000,0x33e00000,0x31000000,RW_NCNB); //bank6-2    MMU_SetMTT(0x33f00000,0x33f00000,0x33f00000,RW_CB);   //bank6-3    MMU_SetMTT(0x38000000,0x3ff00000,0x38000000,RW_NCNB); //bank7        MMU_SetMTT(0x40000000,0x47f00000,0x40000000,RW_NCNB); //SFR    MMU_SetMTT(0x48000000,0x5af00000,0x48000000,RW_NCNB); //SFR    MMU_SetMTT(0x5b000000,0x5b000000,0x5b000000,RW_NCNB); //SFR    MMU_SetMTT(0x5b100000,0xfff00000,0x5b100000,RW_FAULT);//not used        MMU_SetTTBase(_MMUTT_STARTADDRESS);    MMU_SetDomain(0x55555550|DOMAIN1_ATTR|DOMAIN0_ATTR);         //DOMAIN1: no_access, DOMAIN0,2~15=client(AP is checked)    MMU_SetProcessId(0x0);    MMU_EnableAlignFault();            MMU_EnableMMU();    MMU_EnableICache();    MMU_EnableDCache(); //DCache should be turned on after MMU is turned on.}    // attr=RW_CB,RW_CNB,RW_NCNB,RW_FAULTvoid ChangeRomCacheStatus(int attr){    int i,j;    MMU_DisableDCache();    MMU_DisableICache();    //If write-back is used,the DCache should be cleared.    for(i=0;i<64;i++)        for(j=0;j<8;j++)            MMU_CleanInvalidateDCacheIndex((i<<26)|(j<<5));    MMU_InvalidateICache();    MMU_DisableMMU();    MMU_InvalidateTLB();    MMU_SetMTT(0x00000000,0x07f00000,0x00000000,attr);    //bank0    MMU_SetMTT(0x08000000,0x0ff00000,0x08000000,attr);    //bank1    MMU_EnableMMU();    MMU_EnableICache();    MMU_EnableDCache();}        void MMU_SetMTT(int vaddrStart,int vaddrEnd,int paddrStart,int attr){    volatile U32 *pTT;    volatile int i,nSec;    pTT=(U32 *)_MMUTT_STARTADDRESS+(vaddrStart>>20);    nSec=(vaddrEnd>>20)-(vaddrStart>>20);    for(i=0;i<=nSec;i++)*pTT++=attr |(((paddrStart>>20)+i)<<20);}



但是在eboot中使用 的映射就是使用OEMAddresstable来初始化页表,这是wince真正的虚实映射
说道这里OEMAddresstable的虚拟起始地址0x80000000是wince规定的还是本来ARM决定的?
我觉得这个虚拟地址是可以改变的,所以才会可以把物理地址和虚拟地址映射成相等的?
各位有什么看法,多多交流啊。








[解决办法]
个人认为,虚拟内存和物理内存是否相等完全没有关系,ADS下没有操作系统,不需要那么复杂的保护操作,映射成相等可以方便使用,开启了MMU后的cache对系统性能提高不止一点,为的就在开启了MMU的情况下还能向使用物理地址一样使用寄存器地址。
[解决办法]
The kernel creates two ranges of virtual addresses from this table: 

One region, from 0x80000000 to 0x9FFFFFFF, will have caching and buffering enabled. 
The other region, from 0xA0000000 to 0xBFFFFFFF, will have caching and buffering disabled. 

帮助文档中ARM Microprocessor这一章有说明,这个地址应该是ARM决定的,似乎是不可以随便改!
[解决办法]
我还没看到,分还没回来都成乞丐了。
[解决办法]

探讨
还有就是EBoot中的MMU 映射表的问题,我觉得跟ADS也没有什么本质上的差别,只是保障了不和 WinCE 操作系统冲突,关键的是 WinCE 的MMU,WinCE需要进行任务切换和设备访问保护,所以必须对设备的访问权限进行完全的管理,最明显的就是 WinCE 下面通常会使用 CACHE 地址和 非CACHE 地址。

[解决办法]
0x80000000当然是CE的设计要求的,ARM架构没理由做这个限制。CE这样设计的目的是简化底层代码的开发。如果你仔细看wince设置页表的代码(在startup.s中),可以发现OEMAddresstable中相同的物理地址被映射了两遍,第一遍是cached address,第二遍是uncached address。
在一个有操作系统的平台上,使用虚拟地址有很多好处:一个是通过限制进程的可以访问地址空间把不同的进程隔离开,防止它们互相影响;另外一个是可以捕捉程序错误,比如说C/C++程序中很常见的一个错误是访问空指针的内容。访问空指针其实是访问地址零里的内容,在ARM架构中物理地址零是一个有效地址(否则系统无法启动),访问地址零不会引发错误;另一方面一般在C/C++应用程序中访问空指针基本上肯定是程序员的错误,这种错误使用物理地址无法捕捉。启用虚拟地址后,一般进程空间的虚拟地址零不会映射到任何物理页面,程序对空指针地址的访问就会触发Page Fault异常,导致操作系统把它终结。当然启用cache也是另外一个好处。

[解决办法]
http://topic.csdn.net/u/20081217/11/f15fa8e3-6215-4f92-b294-17af5b9b38cb.html
上面这个帖已经结了。
这个帖也相关。都一样。
上次我说我的mboot,boot.bib里0x0开始的。(帮助回忆)
这几天调试新的板子,顺便输出一些函数的地址,发现它的值是0x0开头的,虽然开着MMU,也用地址映射表做了映射0x8开头。
所以 hhyh612 说的看起来是对的?!
如果这个值是boot.bib里影响的。那么你们的代码,在需要调用函数的时候得到一个虚地址,要转换(MMU干的)成物理地址,把代码加载。当关闭MMU前,需要代码做转换,把虚地址转成物理地址。
但是我的代码,在MMU打开的时候,本身函数值就是个物理地址,MMU要做转换吗?感觉就没必要了吧。
[解决办法]
这个问题也一直弄的不是很清楚,趁着这个机会学习下.据我的理解,OEMAddresstable并不是一个完整的页表,它只把虚拟地址的一部分映射到物理地址.
系统为每一个进程都会维护一份页表,在进程切换的时候把不同的页表基地址传MMU.OEMAddresstable的作用是系统在想访问某个确认的物理地址的时候,可以很容易的找到它的虚拟地址,而不需要关心mmu里现在放的是哪个页表.
[解决办法]
总结:填写好二级页表,把二级页表的首地址存放到一级页表的表项最后最后;根据OEMAddresstable初始化L1页表;把L1的转换表的基地址放到协处理器的c1的寄存器。启动MMU等功能即可。 
------
那本《Windows CE工程实践完全解析》中有讲到"二级页表的首地址存放到一级页表的表项最后"!
在第32、第61~第62页

热点排行