微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM中MMU使用实例

ARM中MMU使用实例

时间:11-11 来源:互联网 点击:

am函数的代码如下:

/*

*将第二部分代码复制到SDRAM

*/

void copy_2th_to_sdram(void)

{

unsigned int *pdwSrc= (unsigned int *)2048;

unsigned int *pdwDest = (unsigned int *)0x30004000;

while (pdwSrc < (unsigned int *)4096)

{

*pdwDest = *pdwSrc;

pdwDest++;

pdwSrc++;

}

}

剩下的create_page_table、mmu_init就是本章的重点了,前者用来设置页表,后者用来开启MMU。

先看看create_page_table函数。它用于设置3个区域的地址映射关系。

(1)将虚拟地址0 - (1M - 1)映射到同样的物理地址去,Steppingstone(从0地址开始的4KB内存)就处于这个范围中。使虚拟地址等于物理地址,可以让Steppingstone中的程序(head.s和init.c)在开启MMU前后不需要考虑太多的事情。

(2)GPIO寄存器的起始物理地址范围为0x56000000,将虚拟地址0xA0000000 - (0xA0000000 + 1M - 1)映射到物理地址0x56000000 - (0x56000000 + 1M - 1)。

(3)本开发板中SDRAM的物理地址范围为0x30000000 - 0x33FFFFFF,将虚拟地址0xB0000000 - 0xB3FFFFFF映射到物理地址0x30000000 - 0x33FFFFFF。

create_page_table函数代码如下:

/*

*设置页表

*/

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_SIZE0x00100000

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;

/*

* 0x56000000是GPIO寄存器的起始物理地址,

* GPBCON和GPBDAT这两个寄存器的物理地址0x56000010、0x56000014,

*为了在第二部分程序中能以地址0xA0000010、0xA0000014来操作GPBCON、GPBDAT,

*把从0xA0000000开始的1M虚拟地址空间映射到从0x56000000开始的1M物理地址空间

*/

virtuladdr = 0xA0000000;

physicaladdr = 0x56000000;

*(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \

MMU_SECDESC;

/*

* 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_tlb_base被定义为unsigned long指针,所指向的内存为4字节,刚好是一个描述符的大小。在SDRAM的开始存放页表——第84行令mmu_tlb_base指向SDRAM的起始地址0x30000000。其中最能体现页表结构的代码是第93、104、116行。

*(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \

MMU_SECDESC_WB;

*(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \

MMU_SECDESC;

*(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \

MMU_SECDESC_WB;

虚拟地址的位[31:20]用于索引一级页表,找到它所对应的描述符,对应于“(virtuladdr >> 20)”。

如图7.13所示,段描述符中位[31:20]中保存段的物理地址,对应于“physicaladdr & 0xFFF00000”。

位[11:0]中用来设置段的访问权限,包括所属的域、AP位、C位(是否可Cache)、B位(是否使用Write buffer)——这对应于“MMU_SECDESC”或“MMU_SECDESC_WB”,它们的域都被设置为0,AP位被设为0b11(根据表7.2可知,它所在的域进行权限检查,则读写操作都被允许)。“MMU_SECDESC”中C/B位都没有设置,表示不使用Cache和Write buffer,所以映射寄存器空间时使用“MMU_SECDESC”。“

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top