重点解释MMU, VA, PA地址分配
AB: 32 bit ARM 可寻址范围为:4GB (2^32)
因此:VA 虚拟地址空间为:4GB,将这4GB分成4K * 1M,这样共有4096个1M虚拟地址空间,记为:VA_seg_addr
(其低20比特都为0)
同样:对PA物理地址空间也分为4K *
1M片断;共4096个物理段地址,记为:PA_seg_addr(其低20比特都为0),每个段大小为1MBytes。当然,由于实际的PA物理空间内存都比较小,譬如mini2440上64M
SDRAM,(Bank6),其地址空间为:0x3000 0000 - 0x33ff ffff
而0x4000 0000以上的地址空间为相应的I/O地址空间;
因此,VA
PA地址需要一个转换表,和相应的转换规则:
转换规则如下:
1、转换表的每个子项长度为32bit,即4Bytes,每个子项的值:高12bit指示的为PA_seg_addr;低20bit表示该物理段地址的空间的属性;
2、转换表共有4096个子项,来记录4GBytes
VA地址空间,其对应的索引即为(VA_seg_addr>>20);而由1)得知每个子项为4Bytes,则转换表所占内存空间大小为:4096
* 4Bytes= 16 KBytes。
3、转换表在内存中的基地址,记为:Tab_base_addr,必须保存在MMU的C2寄存器中,约定Tab_base_addr必须是16K字节地址对齐,即Tab_base_addr[13..0]
= 0x0,
C2的[31..14]保存的Tab_base_addr[31..14],其它比特位为属性控制。
4、假设已知Tab_base_addr,VA,PA,需建立该VA与PA之间的映射关系,如何设置转换表:
用C语言表示:
unsigned int *tab = (unsigned
int*)(Tab_base_addr & 0xFFFF
C000);
unsigned int va_index_base =
((VA&0xFFF0 0000) >>
20);
tab[va_index_base] =
(PA&0xFFF0 0000) | 属性值
例如mini2440, Tab_base_addr=0x3000
4000,
VA1=0xC000 0000~ 0xC3FF FFFF
(64M)
PA1=0x3000 0000~ 0x33FF FFFF
(64M)
VA1
PA1
*((unsigned int *)(0x3000
4000[0xC00])) => *(unsigned int *)(0x3000 4000 +
0xC00*4) = 0x3000 0000 + 0x0c1e => 0x3000 0c1e,
记为[0x3000 7000] = 0x3000 0c1e
[0x3000 7000] = 0x3000
0c1e VA: 0xC000 0000 PA: 0x3000
0000
[0x3000 7004] = 0x3010
0c1e VA: 0xC010 0000 PA: 0x3010
0000
[0x3000 7008] = 0x3020
0c1e VA: 0xC020 0000 PA: 0x3020
0000
[0x3000 700c] = 0x3030
0c1e VA: 0xC030 0000 PA: 0x3030
0000
...
[0x3000 70fc] = 0x3030
0c1e VA: 0xC3F0 0000 PA: 0x33F0
0000
VA2=0x3000 0000 ~ 0x300F
FFFF
PA2=0x3000 0000 ~ 0x300F
FFFF
*((unsigned int *)(0x3000
4000[0x300])) => *(unsigned int *)(0x3000 4000 +
0x300*4) = 0x3000 0000 + 0x0c1e => 0x3000 0c1e,
记为[0x3000 4c00] = 0x3000 0c1e
[0x3000 4c00] = 0x3000
0c1e VA: 0x3000
0000 PA: 0x3000 0000
对其他所有未做映射的VA地址空间,需设置属性值为没有使用,譬如:
*((unsigned int *)(0x3000
4000[0x0])) => *(unsigned int *)(0x3000 4000 +
0x0*4) = 0x0;
[0x3000 4000] = 0x0000 0000;
如果对该VA地址进行访问时,系统将触发异常
5、如果转换表已经设置好了,譬如4)中VA1PA1,则当CPU
访问VAx时,系统是如何得到相应的物理空间的呢?
unsigned int va_index = ((VAx&0xFFF0 0000)
>> 20);
unsigned int va_offset = (VAx&0x000F
FFFF);
unsigned int pa_offset = va_offset;
unsigned int pa_seg_addr = [C2(31..14)[va_index]] =([Tab_base_addr
+ va_index<<2] &
0xFFF0 0000);
unsigned int pa = pa_seg_addr | pa_offset;