一、映射过程详解
关于页表:ARMv6的MMU进行地址映射时涉及到两种页表,一级页表(first level page table)和二级页表(coarse page table)。
关于映射方式:映射方式有两种,段映射和页映射。段映射只用到一级页表,页映射用到一级页表和二级页表。
关于映射粒度:段映射的映射粒度有两种,1M section和16M supersection;页映射的映射粒度也有两种,4K small page和64K large page。
硬件在做地址转换时,如何知道当前是什么映射方式以及映射粒度是多少呢?
这些信息可以从页表的入口描述符中获得。
一级页表的入口描述符(first-level descriptor)格式如下:
第[1:0]位决定映射方式:
[1:0]=10b时,是段映射,此时只需作一级映射,描述符的最高12或8位存放的是段基址;
[1:0]=01b时,是页映射,此时虚拟地址转换为物理地址需要经历二级映射,描述符的最高22位存放的是二级页表的物理地址;
第[18]位决定段映射的粒度:
[18]=0b时,映射粒度为1M,描述符的最高12位存放段基址;
[18]=1b时,映射粒度为16M,描述符的最高8位存放段基址;
当映射方式为页映射时,我们用到二级页表,二级页表的入口描述符(second-level descriptor)格式如下:
第[1:0]位决定页映射的映射粒度:
[1:0]=10b或11b时,映射粒度为4KB,描述符的最高20位为页基址;
[1:0]=01b时,映射粒度为64KB,描述符的最高16位为页基址;
下面分4种情况对地址映射过程做详细描述:
1)段映射,映射粒度为1M
2)段映射,映射粒度为16M
3)页映射,映射粒度为4K
4)页映射,映射粒度为64K
1.1段映射,映射粒度为1M
当映射方式为段映射,且映射粒度为1M时,映射图如下:
虚拟地址到物理地址的映射过程如下:
虚拟地址的[31:20]位存放一级页表的入口index,[19:0]位存放段偏移;
从TTBR(translation table base register,协处理器CP15中的一个寄存器,用于存放一级页表的基址)寄存器中获取一级页表的基址;
一级页表基址+ VA[31:20] = 该虚拟地址对应的页表描述符的入口地址;
页表描述符的[31:20]位为该虚拟地址对应的物理段基址;
物理段基址+ VA[19:0]段偏移= 物理地址
由映射图可知,一个虚拟地址可以索引2^12个一级页表入口,每个入口映射2^20大小的内存,故虚拟地址可以映射的最大物理内存为:2^12 * 2^20,即4G。
1.2 段映射,映射粒度为16M
当映射方式为段映射,且映射粒度为16M时,映射图如下:
虚拟地址到物理地址的映射过程如下:
虚拟地址的[31:24]位存放一级页表的入口index,[23:0]位存放段偏移;
从TTBR(translation table base register,协处理器CP15中的一个寄存器,用于存放一级页表的基址)寄存器中获取一级页表的基址;
一级页表基址+ VA[31:24] = 该虚拟地址对应的页表描述符的入口地址;
页表描述符的[31:24]位为该虚拟地址对应的物理段基址;
物理段基址+ VA[23:0]段偏移= 物理地址
由映射图可知,一个虚拟地址可以索引2^8个一级页表入口,每个入口映射2^24大小的内存,故虚拟地址可以映射的最大物理内存为:2^8 * 2^24,即4G。
1.3 页映射,映射粒度为4K
当映射方式为页映射,且映射粒度为4K时,映射图如下:
虚拟地址到物理地址的映射过程如下:
虚拟地址的[31:20]位存放一级页表的入口index,[19:12]位存放二级页表的入口index,[11:0]位存放页偏移;
从TTBR(translation table base register,协处理器CP15中的一个寄存器,用于存放一级页表的基址)寄存器中获取一级页表的基址;
一级页表基址+ VA[31:20] = 一级页表描述符的入口地址;
一级页表描述符的[31:10]位存放二级页表的基址;
二级页表基址+ VA[19:12] = 二级页表描述符的入口地址;
二级页表描述符的[31:12]位存放该虚拟地址在内存中的物理页基址;
物理页基址+ VA[11:0]页偏移= 物理地址
由映射图可知,一个虚拟地址可以索引2^12个一级页表入口,每个一级页表入口指向的二级页表最大可以有2^8个二级页表入口,每个二级页表入口映射2^12大小的内存,故虚拟地址可以映射的最大物理内存为:2^12 * 2^8 * 2^12 ,即4G。
1.4 页映射,映射粒度为64K
当映射方式为页映射,且映射粒度为64K时,映射图如下:
虚拟地址到物理地址的映射过程如下:
虚拟地址的[31:20]位存放一级页表的入口index,[19:16]位存放二级页表的入口index,[15:0]位存放页偏移;
从TTBR(translation table base register,协处理器CP15中的一个寄存器,用于存放一级页表的基址)寄存器中获取一级页表的基址;
一级页表基址+ VA[31:20] = 一级页表描述符的入口地址;
一级页表描述符的[31:10]位存放二级页表的基址;
二级页表基址+ VA[19:16] = 二级页表描述符的入口地址;
二级页表描述符的[31:16]位存放该虚拟地址在内存中的物理页基址;
物理页基址+ VA[15:0]页偏移= 物理地址
由映射图可知,一个虚拟地址可以索引2^12个一级页表入口,每个一级页表入口指向的二级页表最大可以有2^4个二级页表入口,每个二级页表入口映射2^16大小的内存,故虚拟地址可以映射的最大物理内存为:2^12 * 2^4 * 2^16 ,即4G。
1.5 地址映射总图
《ARM1176 JZF-S Technical Reference Manual》中有一张对上述四种映射情况的汇总图:
2. 关于一级页表基址
参考《ARM1176 JZF-S Technical Reference Manual》6.12 MMU descriptors
ARMv6中有两个协处理器寄存器用来存放一级页表基地址,TTBR0和TTBR1。操作系统把虚拟内存划分为内核空间和用户空间,TTBR0存放用户空间的一级页表基址,TTBR1存放内核空间的一级页表基址。
In this model, the virtual address space is divided into two regions: • 0x0 -> 1<<(32-N) that TTBR0 controls • 1<<(32-N) -> 4GB that TTBR1 controls.
N的大小由TTBCR寄存器决定。0x0 -> 1<<(32-N)为用户空间,由TTBR0控制,1<<(32-N) -> 4GB为内核空间,由TTBR1控制。
N的大小与一级页表大小的关系图如下:
操作系统为用户空间的每个进程分配各自的页表,即每个进程的一级页表基址是不一样的,故当发生进程上下文切换时,TTBR0需要被存放当前进程的一级页表基址;TTBR1中存放的是内核空间的一级页表基址,内核空间的一级页表基址是固定的,故TTBR1中的基址值不需要改变。
2.u-boot中MMU初始化代码分析
2.1 start.s中mmu使能
enable_mmu:
/* enable domain access */
ldr r5, =0x0000ffff
mcr p15, 0, r5, c3, c0, 0 @load domain access register
/* Set the TTB register */
ldr r0, _mmu_table_base
ldr r1, =CFG_PHY_UBOOT_BASE
ldr r2, =0xfff00000
bic r0, r0, r2
orr r1, r0, r1
mcr p15, 0, r1, c2, c0, 0
/* Enable the MMU */
mmu_on:
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1
mcr p15, 0, r0, c1, c0, 0
nop
nop
nop
nop
2.2 lowlevlel_init.s中映射表初始化
.macro FL_SECTION_ENTRY base,ap,d,c,b
.word (\base << 20) | (\ap << 10) | \
(\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)
.endm
.macro FL_SECTION_ENTRY base,ap,d,c,b /*.macro指令是汇编中宏定义的意思,此带参宏将FL_SECTION_ENTRY base,ap,d,c,b定义成一个word大小的特定值*/,
.word (\base << 20) | (\ap << 10) | \ /*这个特定值就是转换表的填充量,其中,参数base是映射出来的段地址的基地址,从第20位开始。*/
(\d << 5) | (1<<4) | (\c << 3) | (\b << 2) | (1<<1)/*20位的大小正好是1MB,由此可知转换表中未保留前20位,映射出来的地址之间间隔为1MB*/
/*故这里采用的是段式映射;继续来分析参数,ap是访问控制位,从第10位开始。d、c、b都是一些权限位*/
.endm /*.endm,即结束宏定义*/
注:该宏的用途就是定义一个.word的字段
/*这里开始设置虚拟映射转换表,这里使用的是段式映射模式,即以段(1MB)为单位进行映射*/
/*因此表中的一个单元只能管1MB,整个4G内存需要创建4096个表单元,所以后面采用了循环的方法来创建*/
.section .mmudata, "a"
.align 14
// the following alignment creates the mmu table at address 0x4000.
.globl mmu_table
mmu_table:
.set __base,0 //虚拟地址0开始
// Access for iRAM
.rept 0x100 //循环定义0x100次,定义0x100个 .word .word .word......,
FL_SECTION_ENTRY __base,3,0,0,0 //.word字段中 高12位位物理基地址
.set __base,__base+1 //地址加1
.endr
此处是定义了0x100个.word 表单元,每个表单元对应的虚拟地址和物理地址一致 0x00000000-0x10000000~0x10000000
// Not Allowed
.rept 0x200 - 0x100
.word 0x00000000
.endr
此处循环定义0x100个 0x00000000,即物理地址为0,即虚拟地址 0x10000000-0x20000000无法访问
.set __base,0x200 //物理基地址为0x20000000
// should be accessed
.rept 0x600 - 0x200 //循环0x400次
FL_SECTION_ENTRY __base,3,0,1,1 //定义页表单元,高12位物理地址为base
.set __base,__base+1
.endr
此处实现的映射关系为 虚拟地址0x20000000-0x60000000 对应的物理地址为 0x20000000-0x60000000
.rept 0x800 - 0x600
.word 0x00000000
.endr
虚拟地址 0x60000000-0x80000000空间无法访问
.set __base,0x800
// should be accessed
.rept 0xb00 - 0x800
FL_SECTION_ENTRY __base,3,0,0,0
.set __base,__base+1
.endr
平行映射, 虚拟地址0x80000000-0xb0000000 对应的物理地址为 0x80000000-0xb0000000
.set __base,0xB00
.rept 0xc00 - 0xb00
FL_SECTION_ENTRY __base,3,0,0,0
.set __base,__base+1
.endr
平行映射, 虚拟地址0x80000000-0xb0000000 对应的物理地址为 0x80000000-0xb0000000
.set __base,0xB00
.rept 0xc00 - 0xb00
FL_SECTION_ENTRY __base,3,0,0,0
.set __base,__base+1
.endr
.set __base,0x200
// 256MB for SDRAM with cacheable
.rept 0xD00 - 0xC00
FL_SECTION_ENTRY __base,3,0,1,1
.set __base,__base+1
.endr
此处实现映射 虚拟地址0xc0000000-0xd0000000 物理地址 0x20000000-0x30000000
VA PA length
0-10000000 0-10000000 256MB
10000000-20000000 0 256MB
20000000-60000000 20000000-60000000 1GB 512-1.5G
60000000-80000000 0 512MB 1.5G-2G
80000000-b0000000 80000000-b0000000 768MB 2G-2.75G
b0000000-c0000000 b0000000-c0000000 256MB 2.75G-3G
c0000000-d0000000 20000000-30000000 256MB 3G-3.25G
转自:https://www.cnblogs.com/tanghuimin0713/p/3917178.html