MMU初始化

来源:互联网 发布:宁波奥凯网络 编辑:程序博客网 时间:2024/05/20 12:48

MMU是Memory Management Unit的缩写,中文名是内存管理单元,它是中央处理器(CPU)中用来管理虚拟存储器、物理存储器的控制线路,同时也负责虚拟地址映射为物理地址,以及提供硬件机制的内存访问授权。

ARM cpu地址转换涉及到三种地址:虚拟地址VA,变换后的虚拟地址MVA,物理地址PA。没有启动mmu之前,cpu核心、cache、mmu、外设等所有部件使用的是物理地址。启动mmu后,cpu核心对外发出虚拟地址VA;VA被转换为MVA供cache,mmu使用,在这里MVA被转换为PA;最后使用物理地址PA读取实际设备。
MVA是除cpu外的其它设备看到的虚拟地址, VA->MVA的方法(硬件自动完成):

if(VA<32M)    MVA=VA|(PID<<25) //PID为进程标识号,通过读CP15的C13获得 else    MVA=PA

使用MVA而不使用VA的原因是当有重叠的VA时,转换为MVA后的地址并不重叠,减少了转换为PA的代价。
(只转小于32M的部分的理解:因为在快速上下文切换中进程只有32M虚拟空间。从0到32M-1,这个是基本条件。所有的进程虚拟空间都是一样的,这样是为了物理空间可以不重合,方便调度,所以低位相同,传给mmu的时候只要VA的高7位为pid就能自动区分了。就是MVA=VA+pid<<25. 当VA大于32M的话,那就不一定是本进程的空间了,也没法转化成MVA了。所以当VA大于32M的时候可能是访问了别的进程空间了。只要不是访问0进程就可以了。)


MVA到PA的转换:

arm系统支持三种转换方式:①段转换②粗页转换③细页转换,至于采用哪种方式由我们在建立页表的时候决定。页表由一个个条目(也称为描述符)组成,每个条目存储一段虚拟地址对应的物理地址及访问权限,或者下一级页表的地址,段转换用到一级页表;页转换用到两级页表。

页表基地址TTB表示一级页表的基地址,它是存储在协处理器CP15的C2寄存器(称为页表基址寄存器)的,一级页表的基地址TTB是16k对齐,也即后14位为0,使用[31:14]存储页表基地址,[13:0]为0.一级页表每个描述符对应1M的虚拟地址,共使用了4096个描述符,因此可以表示4G空间。

进行MVA到PA的转换,首先页表基址寄存器[31:14]和虚拟地址MVA[31:20]组成一个低两位为0的32位地址,MMU根据这个地址可以找到这个地址对应的描述符。

这里写图片描述

根据这个描述符可以知道采用的转换方式为段转换或者粗页转换或者细页转换,描述符的结构有以下几种:

这里写图片描述

因此描述符末两位为01的表示采用的是粗页转换;10的是段转换;11的是细页转换。
段转换:如果采用的是段转换,则MMU取出段描述符的[31:20](由图可知这12位存储的是段基地址),和虚拟地址MVA[19:0]组成一个32位的地址,该地址就是MVA对应的物理地址PA。
粗页转换:如果采用的是粗页转换,则MMU取出描述符的[31:10](二级页表的基地址),和虚拟地址MVA[19:12]组成一个低两位[1:0]为0的地址,该地址是MVA对应的二级页表的描述符的地址,根据该地址可以得到二级描述符。二级描述符的格式为:

这里写图片描述

其中粗页转换的是对应大页转换和小页转换。
大页转换:取出大页描述符中的bits[31:16]——大页基址,它和MVA的bits[15:0]组成一个32位的物理地址,这就是MVA对应的PA。大页转换中MVA的位有重合,bits[15:12],当这四位由0000——1111变化时,返回的大页描述符相同,所以粗页表中连续16个条目都保存同一个大页描述符。
小页转换:取出bits[31:12]与MVA的bits[11:0]组成一个32位的地址,这就是MVA对应的PA。
细页转换:如果采用的是细页转换,则MMU取出描述符[31:12]和虚拟地址MVA[19:10]组成低两位为0的地址,根据该地址寻找到二级描述符,该二级描述符对应这极小页转换。取出二级描述符[31:10]和虚拟地址MVA[9:0]组成一个物理地址,该地址就是MVA对应的物理地址。


MMU初始化
以段转换为例,需要做的工作是:
①建立一级页表
②写入TTB
③使能MMU
代码:

/* 用于段描述符的一些宏定义 */ #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 << 0)         /* 段描述符 */#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)void create_page_table(void){    unsigned long *ttb = (unsigned long *)0x30000000;    unsigned long vaddr, paddr;    vaddr = 0xA0000000;    paddr = 0x56000000;    *(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC;/*不理解为什么是右移20位而不是右移18位,然后最后两位补0*/    vaddr = 0x30000000;    paddr = 0x30000000;    while (vaddr < 0x34000000)    {        *(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC_WB;        vaddr += 0x100000;        paddr += 0x100000;    }}void mmu_init(){   __asm__(    /*设置TTB*/    "ldr    r0, =0x30000000\n"                      "mcr    p15, 0, r0, c2, c0, 0\n"          /*域domain和AP共同决定了段的访问权限。ARM系统把整个存储空间分为16个域,每个域通过两个位来决定它的访问权限,访问权限存储在CP15的r3寄存器里。这里设置为不进行权限检查*/    "mvn    r0, #0\n"                       "mcr    p15, 0, r0, c3, c0, 0\n"      /*使能MMU*/    "mrc    p15, 0, r0, c1, c0, 0\n"        "orr    r0, r0, #0x0001\n"              "mcr    p15, 0, r0, c1, c0, 0\n"        :     :   );}

注:bootloader中一般不使用mmu,所以可以先不调用函数。

0 0
原创粉丝点击