来源:百问网_嵌入式Linux wiki_jz2440 新1期视频维基教程 (视频文字版)

本文字数:2505,阅读时长:2.5分钟
这节课开始编写MMU代码,从上一个程序的基础上修改。
首先打开Start.S,我们需要创建页表,启动MMU,页表是保存在SDRAM里面的,也就在内存初始化之后,创建页表。
/* 创建页表 */ bl create_page_table /* 启动MMU */ bl mmu_enable
新建一个mmu.c文件。
在创建一个一级页表前,我们要先确定要映射哪些虚拟地址(VA),映射到哪个物理地址(VB),类型是否使用Cache和Buffer(CB)。
我们程序一开始运行是从0地址开始运行,为了保证使能MMU后,前后的地址保持一致,0地址这段我们需要映射。
在做了一些初始化后,会用到栈,如果是nor启动,栈是0x40000000开始。
VA PA CB 0 0 00 0x40000000 0x40000000 11
然后映射64M的SDRAM:
64M sdram: VA PA CB 0x30000000 0x30000000 11 ...... 0x33f00000 0x33f00000 11
接着是映射寄存器,且不应该使用Cache和Buffer:
register: 0x48000000~0x5B00001C VA PA CB 0x48000000 0x48000000 00 ....... 0x5B000000 0x5B000000 00
涉及LCD的话,还有Framebuffer:
Framebuffer : 0x33c00000 VA PA CB 0x33c00000 0x33c00000 00
同时,为了验证映射成功,先修改链接脚本中的链接地址为0xB00000000,再对应的映射0xB00000000到原来的0x300000000:
link address: VA PA CB 0xB0000000 0x30000000 11
根据上一节的“Section”格式,将每位的操作定义成宏:
#define MMU_SECDESC_AP (3<<10) #define MMU_SECDESC_DOMAIN (0<<5) #define MMU_SECDESC_NCNB (0<<2) #define MMU_SECDESC_WB (3<<2) #define MMU_SECDESC_TYPE ((1<<4) | (1<<1)) #define MMU_SECDESC_FOR_IO (MMU_SECDESC_AP | MMU_SECDESC_DOMAIN | MMU_SECDESC_NCNB | MMU_SECDESC_TYPE) #define MMU_SECDESC_FOR_MEM (MMU_SECDESC_AP | MMU_SECDESC_DOMAIN | MMU_SECDESC_WB | MMU_SECDESC_TYPE)
设置页表的第一步,就是设置页表保存的位置在哪,随便选择一个没使用过的空间即可,大小为16K:
/* ttb: translation table base */ unsigned int *ttb = (unsigned int *)0x32000000;
第二步就是根据va,pa依次设置页表条目,这里我们写个函数来完成对应关系:
#define IO 1 #define MEM 0 void create_secdesc(unsigned int *ttb, unsigned int va, unsigned int pa, int io) { int index; index = va / 0x100000; if (io) ttb[index] = (pa & 0xfff00000) | MMU_SECDESC_FOR_IO; else ttb[index] = (pa & 0xfff00000) | MMU_SECDESC_FOR_MEM; }
然后依次映射每个页表条目:
/* 2.1 for sram/nor flash */ create_secdesc(ttb, 0, 0, IO); /* 2.2 for sram when nor boot */ create_secdesc(ttb, 0x40000000, 0x40000000, MEM); /* 2.3 for 64M sdram */ va = 0x30000000; pa = 0x30000000; for (; va < 0x34000000;) { create_secdesc(ttb, va, pa, MEM); va += 0x100000; pa += 0x100000; } /* 2.4 for register: 0x48000000~0x5B00001C */ va = 0x48000000; pa = 0x48000000; for (; va <= 0x5B000000;) { create_secdesc(ttb, va, pa, IO); va += 0x100000; pa += 0x100000; } /* 2.5 for Framebuffer : 0x33c00000 */ create_secdesc(ttb, 0x33c00000, 0x33c00000, IO); /* 2.6 for link address */ create_secdesc(ttb, 0xB0000000, 0x30000000, MEM);
至此,我们完成了MMU的设置,还需要使能MMU。 在Start.S里面添加mmu_enable,需要做的步骤有: 1.把页表基址告诉cp15 2.设置域为0xffffffff, 不进行权限检查 3.使能icache,dcache,mmu 4.返回到之前位置
mmu_enable: /* 把页表基址告诉cp15 */ ldr r0, =0x32000000 mcr p15, 0, r0, c2, c0, 0 /* 设置域为0xffffffff, 不进行权限检查 */ ldr r0, =0xffffffff mcr p15, 0, r0, c3, c0, 0 /* 使能icache,dcache,mmu */ mrc p15, 0, r0, c1, c0, 0 orr r0, r0, #(1<<12) /* enable icache */ orr r0, r0, #(1<<2) /* enable dcache */ orr r0, r0, #(1<<0) /* enable mmu */ mcr p15, 0, r0, c1, c0, 0 mov pc, lr
最后修改Makefile,添加mmu.o进行测试。
「新品首发」STM32MP157开发板火爆预售!首批仅300套


还没有评论,来说两句吧...