一、ARM中对于存储管理的协处理器CP15
CP15可以包含16个32bit的寄存器,分别标记为0~15。但是对于同一个寄存器的物理寄存器可能会对应多个。
实际上对于CP15的访问的指令相当简单,只有MCR于MRC。并且这两个指令的格式是相同的。
MCR/MRC{<cond>} p15, 0 ,<Rd>,<CRn>,<CRm>{,<opcode_2>}
其中Rd 为ARM的寄存器,CRn和CRm为协处理寄存器。CRn为主,而CRm与opcode_2为辅助寄存器,主要区分同一编号的不同寄存器。如果不需要的情况下CRm为C0,而opcode_2为0;
其中c1寄存器的bit0为禁止或者使能MMU。
如使能MMU:
MRCP15,0,R0,C1,C0,0
ORR R0,#01
MCRP15,0,R0,C1,C0,0
二、MMU的地址变换
ARM中TTB(Translation Table Base)中存储了段描述符的物理地址,它必须与16KB对齐,所以低14bit都是零。如下图所示
它将4GB的空间划分为4096X32bit的区域虚拟寻址。这种寻址方式又分为两个步骤进行,分别为一级页表查询和二级页表查询。
下图为整个寻址方式的总框图:
从图中我们可以清楚的看到页表的查询分为直接的section base查询和基于二级页表的查询。下面将对这两种查询方式分别讨论和讲解。
1 基于section base的段基地址查询方式
这种方式是MMU里面最为简单的,也是用的最多的一种查询方式,它没有二级页表,在虚拟到物理地址的转换过程中加载了一部分访问权限。
当CPU从CP15-C2寄存器中读取TTB地址之后,如上图所示,将通过virtual address的[31:20]进行索引,这个索引所需要的地址当然也就是由这两部分合成的地址。具体的合成方法如下:
如图所示,最后的索引值(也就是所谓的地址转换条目地址)高16bit是由TTB的高16bit组成,而[13:2]是virtual address的高12bit,剩下的[1:0]保持为0(实际如果你对ARM创建这些东西原因有所研究就不难发现这其实就是为了32bit对齐而准备的)。通过这个地址索引便可以找到我们需要的一级描述符,也就是我们框图中的TranslationTable。
而这个一级描述符可能存在几种格式,这几种格式又会代表不同的地址查询方法,如下图所示:
如果[1:0]是00,则表示访问失效,这个时候MMU没有适用这个地址,当然软件就可以使用这块内存了。
如果[1:0]是01,则表示这是二级页表粗颗粒方式(coarse pagetable)
如果[1:0]是10,则表示段组寻址(section base),是我们讨论的重点。
如果 [1:0] 是 11 ,则表示这是二级页表细颗粒方式( fine page table )2 基于二级页表的地址查询方式
Coarsepage 索引了一个二级页表,这个页表描述查询是用大页,小页还是极小页。
同样细颗粒所索引的二级页表也能包括大页,小页和极小页。但是它把1M空间分为1024个1KB。无论是粗颗粒还是细颗粒,都会在一级描述符中返回一个二级描述符,指向不同的控制页面。这些页面又会分为大页(large page),小页(small page)和极小页(tiny page)。具体是哪一种页面根据二级描述符的[1:0]定义,定义如下:
其中大页是64KB对齐,小页是4KB对齐,而极小页是1KB对齐的。对于粗颗粒只提供大页和小页对齐,而细颗粒可提供极小页对齐。
下面将是一个细页寻址的流程,从图中我们可以清楚的看到它的查询方式:
通过20位至31位寻址一级页表, 一级页表的12位至31位为二级页表的基地址,加上19到11位为偏移就找到了物理基地址,物理基地址+剩下的作为页内偏移就是它的物理地址了。
创建页表
void create_page_table(void)
{
//对我的GPIO进行映射
unsigned long *ttb = (unsigned long *)0x20000000;//建立段描述符的基地址
unsigned long vaddr, paddr; //虚拟地址,物理地址
vaddr = 0xA0000000;
paddr = 0xE0200000;
*(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) | MMU_SECDESC;
//取虚拟地址高12位 将物理基地址取出 权限等的设置
/***********************************************************/
//对我的内存进行映射
vaddr = 0x20000000;
paddr = 0x20000000;
while (vaddr < 0x24000000)
{
*(ttb + (vaddr >> 20)) = (paddr & 0xFFF00000) |MMU_SECDESC_WB;
//使用MMU时通常打开Cache,Write buffer
vaddr += 0x100000; //每一个表项只能映射1M
paddr += 0x100000;
}
}
Cache
用于将常用数据储存便于快速访问
Write buffer
用于内存区暂时无法写入数据时,将数据储存起来,在可以写入数据时,自行写入内存。