ARMv7 MMU多级页表

ARMv7 MMU多级页表

Arm v7-A架构中规定的VMSA(virtual memory space address)可以支持最多两级页表,MMU是具体实现VMSA的器件,本文关注使用MMU实现虚拟地址转换的关键的软件细节。

ARMv7 MMU特性概览

  1. 支持最多2级页表。
  2. 支持长描述符和短描述符2种描述页表项的方式。
  3. 一级页表支持1M或者16M两种size.
  4. 二级页表支持4K或者64K两种size.
  5. 提供虚拟地址转换的同时提供内存区域的权限控制。

对上面的特性做出一些必要的解释:首先2级页表是可配置的,软件可以配置MMU只使用一级页表。其次,长描述符是针对一种叫大内存扩展(Large Physic Address Extension, LPE)的特殊扩展使用的,市面上常见的ARM处理器大概率都没有使用这种扩展。最后,虽然一级页表和二级页表的页尺寸好像是可选的,其实仍然是与LPE扩展有关的,大部分都只支持1M的一级页表和4K的二级页表。

后面的谈论都是在不涉及LPE扩展的前提下。

关键术语的再说明

页表及其相关术语比较通用,为了描述更加准确,ARM文档中做了一些术语的定义和区分:

  1. Translation Table和 Page Table. 常说的页表实际上只有最后一级是真正的页表,前面的若干级都是为了找到最后一级页表的页目录。不管是真正的页表还是页目录都被称为转换表。
  2. Translation Table Entry. 所有的转换表在代码中实现都是一维数组,数组中的每个项,就被称为一个entry.
  3. section和page. 一级转换表对应的范围叫section,二级转换表对应的范围叫page.

1st Translation Table

一级转换表的Entry有四种格式,这些格式可以共存在转换表中。实际使用是是四选一,也就是说,可以将MMU配置成只使用一级转换表(此时就是页表)就完成地址转为;也可以配置成需要查找到二级页表才完成转换。除此之外,当不期望使用某个虚拟地址范围时,可以将其对应的Entry配置成Fault格式,这样当处理器试图访问这些虚拟地址时就会产生异常。
在这里插入图片描述
关于一级转换表有下面一些细节:

  1. 转换表的地址必须按照16KB对齐(因为MMU的寄存器问题,只记录转换表地址的高18位)。
  2. 每个Entry长度为32,也就是一个word的长度。
  3. Entry最低两位表示Entry的类型,这表明不同类型的Entry可以同时存在,软件可以自由选择是否使用二级转换表。
  4. 将4G空间划分为4096个1M的section,也就是一级转换表一共有4096个entry.
  5. 关于supercetion,需要特别强调的是,相当于16个普通的section,需要16个完全相同的Entry,但是MMU中可以识别这是同一个supersection,这样能够加速MMU地址转换的过程(TLB hit),但对软件来说并不会节省管理内存。
//主要的几个格式的映射
unsigned L1_MMU_TT[4096] __attribute__((align(16*1024));

void mapping_L1_section(unsigned va_start, unsigned pa_start, unsigned size, unsigned attr)
{
	unsigned index = Value(High_12_bits(va_start));
	unsigned num_entry_needed = size/1024/1024; //或者size>>20,计算需要多少个1M section
	for(auto i=0; i<num_entry_needed; i++)
	{
		L1_MMU_TT[index+i] = High_12_bits(pa_start) | LOW_20_bits(attr);
		pa_start += 1024*1024;//物理地址移动1M
	}
}

void mapping_L1_supersection(unsigned va_start, unsigned pa_start, unsigned size, unsigned attr)
{
	unsigned index = Value(High_8_bits(va_start));
	unsigned num_entry_needed = size/16/1024/1024;
	for(auto i=0; i<num_entry_needed; i++)
	{
		for(int j=0;j<16;j++)
		{
			//需要连续16个entry,每个entry完全相同
			L1_MMU_TT[index+i*16+j] = High_8_bits(pa_start) | LOW_24_bits(attr);
		}
		pa_start += 16*1024*1024; //物理地址移动16M
	}
}

void mapping_L1_L2d(unsigned va_start, unsigned l2_addr, unsigned attr)
{
	unsigned index = Value(High_12_bits(va_start));
	L1_MMU_TT[index] = High_22_bits(l2_addr) | LOW_10_bits(attr);
}

2nd Translation Table

二级转换表的Entry有三种格式,同样地,这三种格式理论上是可以同时存在于二级转换表的,此外,每个entry也是三选一。Large Page是64K,Small Page是4K.
在这里插入图片描述
关于二级转换表,下面这些要注意细节:

  1. 二级转换表(页表)是有很多个的,每个一级页表都对应一个二级页表数组。
  2. 二级页表的每个entry为1个word,也就4字节。
  3. 每个二级页表都有256个entry(无论是large page还是small page),也就是说每个二级页表都占1KB内存。
  4. Large Page与前文的Super Section一样,同样需要占用多个entry,这里是16个二级页表的entry. 这样能够使得MMU TLB hit概率变大,加速地址转换过程,并不会节省页表大小。
//二级页表的主要映射操作
void mapping_L2_Small(unsigned *pageTableAddr, unsigned va_start, unsigned pa_start, unsigned size, unsigned attr)
{
	unsigned index = Value(High_20_bits(va_start));
	unsigned num_page_needed = size/4/1024;
	for(auto i=0; i<num_page_needed; i++)
	{
		*(pageTableAddr+index+i) = High_20_bits(pa_start) | Low_12_bits(attr);
		pa_start += 4*1024; //物理地址移动4K
	}
}

void mapping_L2_Large(unsigned *pageTableAddr, unsigned va_start, unsigned pa_start, unsigned size, unsigned attr)
{
	unsigned index = Value(High_20_bits(va_start));
	unsigned num_page_needed = size/64/1024;
	for(auto i=0; i<num_page_needed; i++)
	{
		for(auto j=0; j<16; j++)
		{
			//需要连续16个entry,每个entry完全相同
			*(pageTableAddr+index+i*16+j) = High_20_bits(pa_start) | Low_12_bits(attr);
		}
		pa_start += 64*1024; //物理地址移动64KB
	}
}

仅使用1st Translation Table映射过程

当entry的格式为section格式时,也就是低2位为10时,就发生如图的过程。图中TB时Taslation Table的缩写。整体过程再简单描述一下:

  1. 需要将一级转换表的基地址告诉给MMU的对应寄存器(需要软件显示操作MMU寄存器),应为这个寄存器只保留高18位,所有转换表的起始地址必须是16K对齐的(画图的时候算错了
  2. 转换时,拿到虚拟地址的高12位,作为index,找到对应的entry:l1_mmu_tt[index].
  3. 对应的entry如果最低2位为10,表示是section格式,也就是说直接替换虚拟地址的高12位即可得到物理地址。
  4. 从entry中取出对应的高12位,替换。
    在这里插入图片描述

使用两级Translation Table映射过程

要使用2级Translation,也就是常说的2级页表,需要第一级对应的entry的最低2位为01,表示entry指向一个2级页表的描述符。整体过程再简单描述一下:

  1. 首先将一级页表的基地址告诉MMU的寄存器TTBR(需要软件显示操作MMU寄存器),注意一级页表需要按照16KB对齐,原因已经阐述过。
  2. 通过虚拟地址的高12位作为index,找到对应的L1 entry: l1_mmu_tt[index],对应的entry最低2位为01.
  3. 从L1 entry的高22位拿到对应的L2 Translation Table基地址.。因此L2 Table必须是按照4KB对齐的,因为L1 entry只记录其地址的高22位。
  4. 通过虚拟地址的中间10位作为index,找到对应的L2 entry.
  5. 将虚拟地址的高22位替换成为L2 entry的高22位即得到物理地址(如果是small page,entry的最低两位为1x(11或10)。large page类似,替换高16位即可。
    在这里插入图片描述

下一步更新计划

  1. 页表配置时机与细节
    代码是运行在虚拟地址空间中的,页表配置也是代码,需要考虑清楚一个问题,页表是什么时候配置的,不然就会面临鸡生蛋问题。
  2. MMU的TLB一致性问题
    TLB是页表的缓存,当页表发生变化时,如果缓存没有跟着变化,那么就将发生错误的地址翻译。
  3. MMU硬件的操作指令。
  4. MMU与特权级的关系。
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值