发新帖我要提问
12
返回列表
打印
[应用相关]

arm的mmu学习

[复制链接]
楼主: wowu
手机看帖
扫描二维码
随时随地手机跟帖
21
wowu|  楼主 | 2019-7-9 09:54 | 只看该作者 |只看大图 回帖奖励 |倒序浏览

[0-1]用来识别页表类型,比如段式,大页,小页等

[2-3]用来识别是否使能cache和write buffer

TEX是扩展的类型字段。


使用特权

评论回复
22
wowu|  楼主 | 2019-7-9 09:54 | 只看该作者

[4-5]是用来做权限管理的

其中S R是在cp15的c1协处理器中,用来做系统保护和rom保护的。


使用特权

评论回复
23
wowu|  楼主 | 2019-7-9 09:55 | 只看该作者

nG   S   XN

其余的就是不同大小的页的基地址。


使用特权

评论回复
24
wowu|  楼主 | 2019-7-9 09:55 | 只看该作者

以64KB管理的二级粗页表的映射形式。


使用特权

评论回复
25
wowu|  楼主 | 2019-7-9 09:56 | 只看该作者

以4KB管理的二级粗页表的映射形式。


使用特权

评论回复
26
wowu|  楼主 | 2019-7-9 09:56 | 只看该作者
4.编程实践


下面使用上面讲的最详细的段页表为例,在裸机的情况下开启MMU,实现虚拟地址映射。

 在现代处理器中,为了使内存的速度跟得上CPU的速度,通常在芯片内部做了缓存(cache)。在启动了cache后,程序的运行效率会极大的提高。

arm中又把cache分为指令cache,又称(icache),和数据cache,又称(dcache)。

其中icache可以随时开启,随时关闭,但dcache必须在开启了MMU后,才能启动。

在启动cache后,arm其实才可以称为哈佛结构(数据指令分开)

否则,在不开启的情况下,其实还是冯洛伊曼结构。

 

我的ddr的地址范围是0x3000000~0x4fffffff

为了验证我的MMU确实开启了,所以把程序的链接地址改为了0xB0000000,同时把0xB0000000起始的1M空间(我的裸机程序很小,远小于1M)映射到了0x30000000

使用特权

评论回复
27
wowu|  楼主 | 2019-7-9 09:56 | 只看该作者
首先看一下我的链接脚本


SECTIONS
{
        . = 0xb0000000;
        __code_start = .;
        . = ALIGN(4);
        .text :
        {
                start.o
                *(.text)
        }
        . = ALIGN(4);
        .rodata :
        {
                *(.rodata)
        }
        . = ALIGN(4);
        .data :
        {
                data_load_add = LOADADDR(.data);
                data_start = .;
                *(.data)
                data_end = .;
        }
        . = ALIGN(4);
        .bss :
        {
                bss_start = .;
                *(.bss) *(.COMMON)
                bss_end = .;
        }
}


使用特权

评论回复
28
wowu|  楼主 | 2019-7-9 09:57 | 只看该作者
接下来是页表的建立。

因为我在裸机中并没有使用很多东西,所以映射的不是所有4G空间,只映射了我用到的。


#define MMU_SECTION_AP                                (0x3<<10)
#define MMU_SECTION_DOMAIN                        (0<<5)
#define MMU_SECTION_NCNB                        (0<<2)
#define MMU_SECTION_ECEB                        (0x3<<2)
#define MMU_SECTION_TYPE                        ((1<<4)|(1<<1))

#define MMU_SECTION_IO        (MMU_SECTION_AP|MMU_SECTION_DOMAIN|MMU_SECTION_NCNB|MMU_SECTION_TYPE)
#define MMU_SECTION_MEM        (MMU_SECTION_AP|MMU_SECTION_DOMAIN|MMU_SECTION_ECEB|MMU_SECTION_TYPE)


#define MMU_IO        1
#define MMU_MEM        0



/* 虚拟地址向物理地址映射 */
static void create_tlb(unsigned int *ttb,unsigned int va,unsigned int pa, int io)
{
        int index;

        index = va / 0x100000;

        if(io)
                ttb[index] = (pa & 0xfff00000) | MMU_SECTION_IO;
        else
                ttb[index] = (pa & 0xfff00000) | MMU_SECTION_MEM;
}


/*        创建一级页表
*  VA                        PA                        CB
*        0                        0                        11
*       
*        512M
*        0x30000000        0x30000000        11
*        ......
*        0x4ff00000        0x4ff00000        11
*       
*  0xd0000000        0xd0000000        11
*
*        SFR
*        0xe0000000        0xe0000000        00
*        ......
*        0xfff00000        0xfff00000        00
*
*        framebuffer
*        0x40000000        0x40000000        00
*
*        link address
*  0xb0000000  0x30000000  11
*/

/* 创建一个一级的段页表 */
void create_page_table(void)
{
        /* 页表在哪 0x4f000000  16k对齐 */
        unsigned int *ttb = (unsigned int *)0x4f000000;
        unsigned int va,pa;

        /*         1.irom */
        create_tlb(ttb,0,0,MMU_MEM);

        /*  2.sdram 512M*/
        va = 0x30000000;
        pa = 0x30000000;
        for( va = 0x30000000; va < 0x4fffffff; va += 0x100000 )
        {
                create_tlb(ttb,va,pa, MMU_MEM);
                pa += 0x100000;
        }

        /* 3.irom/iram */
        create_tlb(ttb,0xd0000000,0xd0000000, MMU_MEM);

        /* 4.sfr */
        va = 0xe0000000;
        pa = 0xe0000000;
        for( va = 0xe0000000; va < 0xfff00000; va += 0x100000)
        {
                create_tlb(ttb,va,pa, MMU_IO);
                pa += 0x100000;
        }

        /* 5.framebuffer */
        create_tlb(ttb, 0x40000000,0x40000000, MMU_IO);

        /* 6. link address */
        create_tlb(ttb,0xb0000000,0x30000000, MMU_MEM);
}

使用特权

评论回复
29
wowu|  楼主 | 2019-7-9 09:57 | 只看该作者
下面是初始化部分(bootloader)


__reset_exception:

        /* 开发板制锁*/
        ldr r0, = 0xe010e81c
        ldr r1, = 0x301
        str r1, [r0]

        /* 关闭看门狗 */
        ldr r0, = 0xe2700000
        mov r1, #0
        str r1, [r0]

        /* 下面有调用c函数设置SVC栈地址 */
        ldr sp, = 0xd0037d80

        /* 启动icache */
        bl enable_icache
       
        /* 设置时钟 */
        bl init_clock

        /* 初始化DDR */
        bl sdram_init

        /* 创建页表 */
        bl create_page_table
       
        /* 使能mmu */
        bl enable_mmu

        /* 代码重定位 */
        bl copy2sdram

        /* 清bss段 */
        bl clear_bss
       
        /* 从iram跳转到ddr */
        ldr pc, = sdram
sdram:
        bl uart0_init

        /* 开irq中断 */
        mrs r0, cpsr
        bic r0, r0, #1<<7
        msr cpsr, r0

        ldr sp, = 0x45000000
       
        /* 调用main函数 */
        bl main

        b .

enable_icache:
        mrc p15, 0, r1, c1, c0, 0         @read Control Regist
        orr r1, r1,#(1<<12)                        @ENABLE instructon cache
        //bic r1, r1,#(1<<12)
        mcr p15, 0, r1, c1, c0, 0
        mov pc, lr

enable_mmu:
        /* translation table base write cp5 */
        ldr r1, = 0x4f000000
        mrc p15, 0, r2, c2, c0, 0         @ Read Translation Table Base Register
        orr r2, r2, r1
        mcr p15, 0, r2, c2, c0, 0         @ Write Translation Table Base Register

        /* set domain 0xffffffff */
        ldr r0, = 0xffffffff
        mcr p15, 0, r0, c3, c0, 0 @ Read Domain Access Control Register


        /* enable i/d canche */
        mrc p15, 0, r1, c1, c0, 0         @Read Control Regist
        orr r1, r1,#(1<<12)                        @enable instructon cache
        orr r1, r1,#(1<<2)                        @enable data cache
        orr r1, r1,#(1<<0)                        @enable mmu
        mcr p15, 0, r1, c1, c0, 0   @write Control Regist
        mov pc, lr

使用特权

评论回复
30
wowu|  楼主 | 2019-7-9 09:58 | 只看该作者
初始化要注意的点:

1.sdram标号之前的代码都应该是位置无关码(不能使用全局变量,静态变量,字符串,初始化过的局部数组等)。

2.因为页表放置在ddr中,所以创建页表必须在ddr初始化之后。

3.因为我的链接地址在0xB0000000,所以代码重定位时必须要能使用0xB0000000的空间。所以我把启动mmu放在了,重定位前面。同时开启MMU时要使用页表基地址,所以页表也必须在开启MMUq前先建立。


使用特权

评论回复
31
wowu|  楼主 | 2019-7-9 09:58 | 只看该作者
5.效果

启动了MMU前,我的刷屏速度大概在每秒几帧。

开启了MMU和cache后,我的刷屏速度差不多可以达到每秒二十对帧。

 

有一点要说明的是,我把framebuffer的显存映射成MEM即可以使用cache和buffer后,刷新速度感觉比映射成IO速度快了一倍。

主要原因是因为我是一整屏的刷颜色,所以dcache很快就满了,然后硬件自动把整个dcache刷回内存。所以速度比直接访问的IO要快,当

每次只刷一小块部分,速度反而会比IO方式慢。

使用特权

评论回复
32
磨砂| | 2019-8-7 09:55 | 只看该作者
长知识了 谢谢

使用特权

评论回复
33
晓伍| | 2019-8-7 09:57 | 只看该作者
我来被扫盲了

使用特权

评论回复
34
观海| | 2019-8-7 10:33 | 只看该作者
我也来扫盲

使用特权

评论回复
35
guanjiaer| | 2019-8-7 10:37 | 只看该作者
是不是很少用到这个啊

使用特权

评论回复
36
heimaojingzhang| | 2019-8-7 10:46 | 只看该作者
非常感谢楼主分享

使用特权

评论回复
37
wowu|  楼主 | 2019-8-7 11:36 | 只看该作者
感谢各位支持

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则