天天看点

linux mmu源码分析,Linux kernel 2.6.29 - head.S 分析 VA PA, MMU 映射分析

重点解释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;