5
回答
关于MMU映射 建表的问题
华为云4核8G,高性能云服务器,免费试用   

#define MMU_FULL_ACCESS     (3 << 10)   /* 访问权限 */
#define MMU_DOMAIN          (0 << 5)    /* 属于哪个域 */
#define MMU_SPECIAL         (1 << 4)    /* 必须是1 */
#define MMU_CACHEABLE       (1 << 3)    /* cacheable */
#define MMU_BUFFERABLE      (1 << 2)    /* bufferable */
#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

    unsigned long virtuladdr, physicaladdr;
    unsigned long *mmu_tlb_base = (unsigned long *)0x30000000;
   
    /*
     * Steppingstone的起始物理地址为0,第一部分程序的起始运行地址也是0,
     * 为了在开启MMU后仍能运行第一部分的程
     * 将0~1M的虚拟地址映射到同样的物理地址
     */
    virtuladdr = 0;
    physicaladdr = 0;
    *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
                                            MMU_SECDESC_WB;


其中最后一句代码什么意思?  virtuladdr >> 20 位  为0? physicaladdr & 0xFFF00000 相与为0?最后一或赋值又是多少?

不要建议看什么什么书,能回答就回答,不知道别装大蒜!

<无标签>
举报
徐长远
发帖于5年前 5回/974阅
共有5个答案 最后回答: 1年前

这事你还真得在看书。MMU的页表映射什么的,你肯定要再看一下,另外C的编程方法,也要找点书补充一下。后者很重要。

编程是在描述逻辑。精简、合并的事情,编译器会帮你做好。如果你的代码认为这里在当前阶段恒为0或者没有计算意义,而代码中不把因果联系描述出来,以后出现变化,会死的很难看。

C语言的代码,是用最精简的方式,把逻辑说清楚,这是编程。所谓优化,那是硬件和软件逻辑外加计算数据的拟合。从三个角度相互考虑。

如果你还不理解,我给个简单的例子。

//#define DEBUG
int add(int a,int b){
    int re = a + b;
#ifdef DEBUG
    printf("%d + %d = %d\n",a,b,re);
#endif
    return re;
}
异常时,我们可以用编译时,加define选项的方式,把上面的DEBUG打开。但发布时,你的源码没有必要删除#ifdef 中的内容。虽然它对你的发布代码没有意义,但反过来说,没意义你也可以保留嘛。

你不能因为现在没意义,认为#ifdef不需要,也认为,int re = a + b;不需要。其实这些代码对你的当前正确性和性能没有任何影响,但对你调整成128位加法,或者理解加法是怎么实现的,有意义。呵呵。心胸放宽点。

C语言编写,逻辑清晰的,往往效率优化后最高。别因为某行代码没有逻辑变化认为没有必要。

--- 共有 6 条评论 ---
我土鳖回复 @中山野鬼 : 嗯,那就教教如何查资料、查哪种资料吧。这是基础的搜集信息的能力。 5年前 回复
中山野鬼@我土鳖 找资料的能力,可以教,资料我也找不到。我没闲到看他做的具体是啥。哈。 5年前 回复
我土鳖回复 @中山野鬼 : 那你不如直接告诉他应该找哪个资料。 5年前 回复
中山野鬼回复 @我土鳖 : 我说方法,不说内容。内容,直接找资料对应就行了。 5年前 回复
徐长远亲,你不如更简短的把0放入16位和8位的寄存器来举例! 5年前 回复

MMU是那个叫内存管理单元的东西吧,这个不看芯片的datasheet描述的映射规则和驱动方式,你这程序写的出来就大神了,最后那代码建议你看下手册里面,地址高12位是存啥东西的。physicaladdr & 0xFFF00000明显就是将低20位清零,保留高12位,又从virtuladdr >> 20也是将低20位清零,保留高12位,将高12位的值作为地址的偏差值加到便移地址,从2^20 = 1M推测,那个地址表是按1M的内存来进行查找的,所以初步推测是mmu的表基础地址+虚拟地址/1M的位置为mmu表存放对应物理地址的位置,而物理地址的换算方式是将低20位清零,保留高12位,使用这个值+MMU_SECDESC_WB,不过建议你代码写成这样可读性会高点:

mmu_tlb_base[(virtuladdr >> 20)] = (physicaladdr & 0xFFF00000) + MMU_SECDESC_WB;
还有你问为啥那2个值是0还要移位?看样子那个是例程,所以虚拟地址和物理地址设定初始化为0,而真正写程序的时候,是按需要写上去的。

以上所以分析均为猜测,都可以跳过,直接看芯片的datasheet,上面应该有正确的分析,没的话建议你叫芯片客服帮你解答,搞不定不买他们的芯片。



--- 共有 6 条评论 ---
cut回复 @中山野鬼 : 你这样说可是要得罪很多女程序猿同胞的哦,不过还好我不属于那范围里的。 5年前 回复
中山野鬼回复 @cut : 如果是女人,我劝你改行吧,做些女人该做的事情。这年头比我怪的人不多,你快赶上我了。人怪不好。我都成鬼了。。。 5年前 回复
cut回复 @中山野鬼 : 瓦萨,发现我是朵奇葩耶,呵呵 5年前 回复
中山野鬼回复 @cut : 不信,女人长成这样的,还能搞底层,那一定是朵奇葩,谈不上阅人无数,但我没见过。如果是男人这么打扮,也是朵奇葩,够媚娘,文笔不至于如此犀利。哈哈。 5年前 回复
cut回复 @中山野鬼 : 跟你说这个是我自己的头像,你会不会被囧死呢 5年前 回复

引用来自“cut”的答案

MMU是那个叫内存管理单元的东西吧,这个不看芯片的datasheet描述的映射规则和驱动方式,你这程序写的出来就大神了,最后那代码建议你看下手册里面,地址高12位是存啥东西的。physicaladdr & 0xFFF00000明显就是将低20位清零,保留高12位,又从virtuladdr >> 20也是将低20位清零,保留高12位,将高12位的值作为地址的偏差值加到便移地址,从2^20 = 1M推测,那个地址表是按1M的内存来进行查找的,所以初步推测是mmu的表基础地址+虚拟地址/1M的位置为mmu表存放对应物理地址的位置,而物理地址的换算方式是将低20位清零,保留高12位,使用这个值+MMU_SECDESC_WB,不过建议你代码写成这样可读性会高点:

mmu_tlb_base[(virtuladdr >> 20)] = (physicaladdr & 0xFFF00000) + MMU_SECDESC_WB;
还有你问为啥那2个值是0还要移位?看样子那个是例程,所以虚拟地址和物理地址设定初始化为0,而真正写程序的时候,是按需要写上去的。

以上所以分析均为猜测,都可以跳过,直接看芯片的datasheet,上面应该有正确的分析,没的话建议你叫芯片客服帮你解答,搞不定不买他们的芯片。



至于我的理解不知道你怎么看,mmu_tlb_base  0x30000000是表的首地址,virtuladdr>>20 相当于/1M,每个虚拟地址都会除以1M,然后把地址存到SDRAM中,然而段地址是1M为单位 所以physicaladrr & 0xFFF00000 因为一个虚拟地址范围可在物理地址的0xFFF00000-0xFFF0FFFF  把物理地址存在 *(mmu_tlb_base + (virtuladdr >> 20))(这也就是引用了下指针)可能专业术语不怎么清晰!

引用来自“徐长远”的答案

引用来自“cut”的答案

MMU是那个叫内存管理单元的东西吧,这个不看芯片的datasheet描述的映射规则和驱动方式,你这程序写的出来就大神了,最后那代码建议你看下手册里面,地址高12位是存啥东西的。physicaladdr & 0xFFF00000明显就是将低20位清零,保留高12位,又从virtuladdr >> 20也是将低20位清零,保留高12位,将高12位的值作为地址的偏差值加到便移地址,从2^20 = 1M推测,那个地址表是按1M的内存来进行查找的,所以初步推测是mmu的表基础地址+虚拟地址/1M的位置为mmu表存放对应物理地址的位置,而物理地址的换算方式是将低20位清零,保留高12位,使用这个值+MMU_SECDESC_WB,不过建议你代码写成这样可读性会高点:

mmu_tlb_base[(virtuladdr >> 20)] = (physicaladdr & 0xFFF00000) + MMU_SECDESC_WB;
还有你问为啥那2个值是0还要移位?看样子那个是例程,所以虚拟地址和物理地址设定初始化为0,而真正写程序的时候,是按需要写上去的。

以上所以分析均为猜测,都可以跳过,直接看芯片的datasheet,上面应该有正确的分析,没的话建议你叫芯片客服帮你解答,搞不定不买他们的芯片。



至于我的理解不知道你怎么看,mmu_tlb_base  0x30000000是表的首地址,virtuladdr>>20 相当于/1M,每个虚拟地址都会除以1M,然后把地址存到SDRAM中,然而段地址是1M为单位 所以physicaladrr & 0xFFF00000 因为一个虚拟地址范围可在物理地址的0xFFF00000-0xFFF0FFFF  把物理地址存在 *(mmu_tlb_base + (virtuladdr >> 20))(这也就是引用了下指针)可能专业术语不怎么清晰!
觉得这个不要对着代码猜好,看芯片的datasheet,这个映射规则肯定有写的
--- 共有 2 条评论 ---
cut回复 @徐长远 : 想法一样,但没被验证过,我的想法也是猜的,不过你有硬件烧个程序进去看看就知道 5年前 回复
徐长远所以初步推测是mmu的表基础地址+虚拟地址/1M的位置为mmu表存放对应物理地址的位置,而物理地址的换算方式是将低20位清零,保留高12位 你的这句不也和我的猜想是一样的么! 5年前 回复

我也遇到这个问题了  想必题主现在已经是大神了 不过我也才理解一点 就来强答一发,看看自己能不能梳理出来哈哈,根据前面几个前辈的回答,我的理解是这样的:

pyhsicaladdr & 0xFFF00000 相与之后清零了低20位,保留了物理地址的高12位,在段地址映射的方式下,这个物理地址的高12位就是段基址,即section base address  或了赋值 意即 把这个12位的物理地址存到这个段描述符的[31:20]的位置。

顶部