免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 6539 | 回复: 15
打印 上一主题 下一主题

[C] MMU内存管理,页表的创建,有个问题不懂,求大神解答,谢谢! [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-10-31 23:03 |只看该作者 |倒序浏览

    页大小为1M(本人觉得严格来讲应该是段大小吧),以省去页(段)描叙符
    unsigned long virtualaddr, physicaladdr;//分别表示虚拟地址和物理地址
    unsigned long *mmu_tlb_base = (unsigned long *)0x30000000; //mmu_tlb_base 表示页表的起始地址
   
    virtualaddr = 0;
    physicaladdr = 0;
    *(mmu_tlb_base + (virtualaddr >> 20)) = (physicaladdr & 0xFFF00000) //@1



    virtualaddr = 0xA0000000;
    physicaladdr = 0x56000000;
    *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000)


    virtualaddr = 0xB0000000;
    physicaladdr = 0x30000000;
    while (virtuladdr < 0xB4000000)
    {
        *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000)
        virtuladdr += 0x100000;
        physicaladdr += 0x100000;
    }

求大神帮忙解释下@1处是什么意思?
为什么virtualaddr要右移20位,physicaladdr 要&0xFFF00000,这样做的目的是什么?是怎么做到的?先谢过大家了~~!

论坛徽章:
0
2 [报告]
发表于 2013-10-31 23:09 |只看该作者
额,主要是搞不明白为什么*(mmu_tlb_base + (virtualaddr >> 20)) = (physicaladdr & 0xFFF00000) 这句话就能将页大小设置为1M,大神帮忙解释下~~

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
3 [报告]
发表于 2013-10-31 23:17 |只看该作者
回复 2# 511244213


    这句话根本不能将页大小设置为1M

   而是页大小已经设置为1M时,TLB如何保存VA==>PA的映射关系。

论坛徽章:
0
4 [报告]
发表于 2013-10-31 23:53 |只看该作者
回复 3# 塑料袋 额,但是好像没有其他的语句来设置了,只有一个宏定义,但是整个工程里面没有根本就没有用到这个宏定义,我把整个源码贴上来吧

/*
* 设置页表
*/
void create_page_table(void)
{

/*
* 用于段描述符的一些宏定义
*/
#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 //1M

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

    /*
     * 0x56000000是GPIO寄存器的起始物理地址,
     * GPFCON和GPFDAT这两个寄存器的物理地址0x56000050、0x56000054,
     * 为了在第二部分程序中能以地址0xA0000050、0xA0000054来操作GPFCON、GPFDAT,
     * 把从0xA0000000开始的1M虚拟地址空间映射到从0x56000000开始的1M物理地址空间
     */
    virtuladdr = 0xA0000000;
    physicaladdr = 0x56000000;
    *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
                                                MMU_SECDESC_WB;

    /*
     * SDRAM的物理地址范围是0x30000000~0x33FFFFFF,
     * 将虚拟地址0xB0000000~0xB3FFFFFF映射到物理地址0x30000000~0x33FFFFFF上,
     * 总共64M,涉及64个段描述符
     */
    virtuladdr = 0xB0000000;
    physicaladdr = 0x30000000;
    while (virtuladdr < 0xB4000000)
    {
        *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
                                                MMU_SECDESC_WB;
        virtuladdr += 0x100000;
        physicaladdr += 0x100000;
    }
}

/*
* 启动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 replacement;1 = Round robin replacement
     * V : 表示异常向量表所在的位置,
     *     0 = Low addresses = 0x00000000;1 = High addresses = 0xFFFF0000
     * I : 0 = 关闭ICaches;1 = 开启ICaches
     * R、S : 用来与页表中的描述符一起确定内存的访问权限
     * B : 0 = CPU为小字节序;1 = CPU为大字节序
     * C : 0 = 关闭DCaches;1 = 开启DCaches
     * A : 0 = 数据访问时不进行地址对齐检查;1 = 数据访问时进行地址对齐检查
     * M : 0 = 关闭MMU;1 = 开启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) );
}

create_page_table这个函数是创建页表,mmu_init这个函数是初始化MMU,只有这两个函数涉及到了,其他的地方没有涉及,其实这是个很小的程序,就是通过MMU,用虚拟地址点亮板子上的LED,然后上课我们老师就说了下create_page_table的功能,没有分析代码,顺带提一句,这个老师真他妈坑,上课讲到arm中pc,为什么pc=pc+8都不知道,我说是因为流水线,预取指令了,他还说不是。。。

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
5 [报告]
发表于 2013-11-01 00:43 |只看该作者
回复 4# 511244213

小伙子有前途啊,蛮下功夫的哈,顶!
不过我今天喝多了,刚去厕所吐完,明天给你看哈。

放心,ARMv7是我强项,指定给你解释清楚!

指令指针寄存器=当前指令地址+8,这个确实不完全因为流水线,而是因为历史遗留原因。
早期的ARM流水线短,也不乱序,+8正好能和上取指器对上。
但现代的ARM流水线动辄十几级,而且乱序,+不+8都对不上取指器。

   

论坛徽章:
11
未羊
日期:2013-12-16 12:45:4615-16赛季CBA联赛之青岛
日期:2016-04-11 19:17:4715-16赛季CBA联赛之广夏
日期:2016-04-06 16:34:012015亚冠之卡尔希纳萨夫
日期:2015-11-10 10:04:522015亚冠之大阪钢巴
日期:2015-07-30 18:29:402015亚冠之城南
日期:2015-06-15 17:56:392015亚冠之卡尔希纳萨夫
日期:2015-05-15 15:19:272015亚冠之山东鲁能
日期:2015-05-14 12:38:13金牛座
日期:2014-12-04 15:34:06子鼠
日期:2014-10-16 13:40:4715-16赛季CBA联赛之八一
日期:2016-07-22 09:41:40
6 [报告]
发表于 2013-11-01 09:32 |只看该作者
塑料袋 发表于 2013-11-01 00:43
回复 4# 511244213

但现代的ARM流水线动辄十几级,而且乱序,+不+8都对不上取指器


+8 最多预取三条指令, 怎么支撑十几级流水线?

论坛徽章:
0
7 [报告]
发表于 2013-11-01 09:33 来自手机 |只看该作者
塑料袋 发表于 2013-11-01 00:43:54
回复 4# 511244213[

谢谢大神……我们芯片是s3c2440,arm9,5级流水线,我看网上说arm9为了兼容arm7的三级流水线,好像执行机制差不多,不知道是不是这样,麻烦大神指点下……

论坛徽章:
0
8 [报告]
发表于 2013-11-01 16:53 |只看该作者
回复 7# 511244213


    你要看明白配置MMU的代码,需要对照这款芯片的手册看,你用的是ARM9的处理器,去找到ARM9 CORE手册,里面会有很详细的介绍

论坛徽章:
36
CU大牛徽章
日期:2013-09-18 15:24:20NBA常规赛纪念章
日期:2015-05-04 22:32:03牛市纪念徽章
日期:2015-07-24 12:48:5515-16赛季CBA联赛之辽宁
日期:2016-03-30 09:26:4715-16赛季CBA联赛之北控
日期:2016-03-30 11:26:2315-16赛季CBA联赛之广夏
日期:2016-05-20 15:46:5715-16赛季CBA联赛之吉林
日期:2016-05-24 11:38:0615-16赛季CBA联赛之青岛
日期:2016-05-30 13:41:3215-16赛季CBA联赛之同曦
日期:2016-06-23 16:41:052015年亚洲杯之巴林
日期:2015-02-03 15:05:04CU大牛徽章
日期:2013-09-18 15:24:52CU十二周年纪念徽章
日期:2013-10-24 15:46:53
9 [报告]
发表于 2013-11-01 17:13 |只看该作者
虽然看不懂,不过以后想学arm,顺便mark下看大牛解释。 看你@1处猜测是获取12位的页内偏移地址(猜想线性地址也是10 (pgd)| 10(pte) | 12(offset) )

论坛徽章:
4
戌狗
日期:2013-08-15 18:22:43技术图书徽章
日期:2013-08-21 13:48:45巨蟹座
日期:2013-09-26 17:06:39处女座
日期:2013-12-25 11:26:10
10 [报告]
发表于 2013-11-02 00:29 |只看该作者
这个程序我搞不定,看糊涂了,这什么路数嘛?

1) 搞不清楚他这个1M页大小在哪设置的
2) 明知是GPIO的寄存器,为什么还要设置成MMU_CACHEABLE | MMU_BUFFERABLE
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP