TLB全称是Translation Look-aside Buffer,用来加速页表查找。这里关键的一点是:如果操作系统更改了页表内容,它必须相应的刷新TLB以使CPU不误用过时的表项。
TLB:Translation Lookaside Buffer.
根据功能可以译为快表,直译可以翻译为旁路转换缓冲,也可以把它理解成页表缓冲。里面存放的是一
些页表文件(虚拟地址到物理地址的转换表)。当处理器要在主内存寻址时,不是直接在内存的物理地
址里查找的,而是通过一组虚拟地址转换到主内存的物理地址,TLB就是负责将虚拟内存地址翻译成实
际的物理内存地址,而CPU寻址时会优先在TLB中进行寻址。处理器的性能就和寻址的命中率有很大的
关系。
映射机制必须使一个程序能断言某个地址在其自己的进程空间或地址空间内,并且能够高效的将其转换
为真实的物理地址以访问内存。一个方法是使用一个含有整个空间内所有页的入口(entry)的表(即
页表),每个入口包含这个页的正确物理地址。这很明显是个相当大的数据结构,因而不得不存放于主
存之中。
由于CPU首先接到的是由程序传来的虚拟内存地址,所以CPU必须先到物理内存中取页表,然后对应程
序传来的虚拟页面号,在表里找到对应的物理页面号,最后才能访问实际的物理内存地址,也就是说整
个过程中CPU必须访问两次物理内存(实际上访问的次数更多)。因此,为了减少CPU访问物理内存的次
数,引入TLB。
====================================================
cpu 内存
TLB <============================> 内存页表
L1 Cache <=====>L2 Cache<=========> 内存数据
====================================================
TLB种类
TLB在X86体系的CPU里的实际应用最早是从Intel的486CPU开始的,在X86体系的CPU里边,一般都设
有如下4组TLB:
第一组:缓存一般页表(4K字节页面)的指令页表缓存(Instruction-TLB);
第二组:缓存一般页表(4K字节页面)的数据页表缓存(Data-TLB);
第三组:缓存大尺寸页表(2M/4M字节页面)的指令页表缓存(Instruction-TLB);
第四组:缓存大尺寸页表(2M/4M字节页面)的数据页表缓存(Instruction-TLB);
图中可见,当CPU执行机构收到应用程序发来的虚拟地址后,首先到TLB中查找相应的页表数据,如果
TLB中正好存放着所需的页表,则称为TLB命中(TLB Hit),接下来CPU再依次看TLB中页表所对应的物
理内存地址中的数据是不是已经在一级、二级缓存里了,若没有则到内存中取相应地址所存放的数据。
如果TLB中没有所需的页表,则称为TLB失败(TLB Miss),接下来就必须访问物理内存中存放的页表
,同时更新TLB的页表数据。
既然说TLB是内存里存放的页表的缓存,那么它里边存放的数据实际上和内存页表区的数据是一致的,
在内存的页表区里,每一条记录虚拟页面和物理页框对应关系的记录称之为一个页表条目(Entry),
同样地,在TLB里边也缓存了同样大小的页表条目(Entry)。由于页表条目的大小总是固定不变的,所
以TLB的容量越大,则它所能存放的页表条目数越多(类似于增大CPU一级、二级缓存容量的作用),
这就意味着缓存命中率的增加,这样,就能大大减少CPU直接访问内存的次数,实现了性能提升。
4. TLB的联合方式:
TLB内部存储空间被划分为大小相同的块(即TLB页表条目),这些块的大小=内存的页表区里页表条目
的大小.
所以,就可以在TLB页表条目和内存页表条目间建立一定的相互对应关系。当CPU需要页表数据时,它
必须迅速做出如下的2个判断:一个是所需要的页表是否已缓存在TLB内部(即判断TLB命中或是失败)
,另一个是所需要的页表在TLB内的哪个条目内。为了尽量减少CPU做出这些判断所需的时间,就必须
在TLB页表条目和内存页表条目之间的对应方式上动点脑筋,下面是几种常见的对应关系。
名称
方式
应用
全联合方式
内存页表里的任何一个条目都可能被对应(缓存)到TLB的任何一个条目,TLB内所有条目都可能被对
应到内存页表里的所有条目上。
Athlon XP在L1 指令TLB部分全是这种方式
4路联合方式
只有内存页表区的某些条目可能被缓存到TLB的某4个页表条目所在的块上。
P4处理器一般采用这种方式
6.1.5 MIPS如此设计的起源
为了在尽可能少使用硬件的前提下提供一套与VAX相同的功能,MIPS的设计者们需要找些好办法。由微代码控制的TLB重装入(refill)是不能接受的,因此他们勇敢的迈出了一步:把这个工作交给软件来完成。
这意味着除了有一个寄存器用来存放当前的ASID,MMU器件仅仅是个TLB而已,也就是一个简单的高速、定长的转译表。系统软件可以(通常也就是如此)把TLB作为一个快存来面向常驻内存的页表,然而TLB硬件本身并不能把自己当作快存来使用,而只能这样:当某一个地址无法进行转译时,TLB会触发一个特殊的异常(TLB重装入异常)来引发调用软件程序。不过,TLB的细节设计和相应的控制寄存器上都作了十分周密的考虑,以帮助软件更加富有效率的运行。
6.2 MIPS TLB的特点
MIPS TLB通常都是在芯片上实现的:即使在快存命中的情形下,内存转译也这一步仍然必须进行,因此在机器上这是一个十分重要的“关键路径”(critical path)。这意味着它必须很小,尤其在早期那个年代,因此,把它的规模控制的很小就十分明智。
基本上这是块全相连的存储单元。每个入口都是一块拥有键值(key)域和数据域的关联存储器;当你提供某个键值后,由硬件来进行匹配并给出匹配成功的入口内的数据。通常全相连存储器效率很高但在硬件上过于浪费,而MIPS系列的TLB含有32到64个入口不等;这种规模的存储量在芯片设计中是相对容易处理的。
R4000风格的CPU至今都在使用这样一种TLB:每个入口内容被扩大为2倍以容纳2个各自映射独立物理页的连续的VPN。这种成对的入口仅增添了很少的硬件逻辑但却加倍了TLB可以装入的映射页,避免了对TLB的设计进行大幅度的调整。
您可以看到为何被称为“全相连”,这强调了所有的键值实际上是并行对输入值进行比较的。
图6.3
TLB的入口如图6-3中所示(您可以在后面的6.5节中找到其详细的编程信息)。TLB的键值包含了以下内容:
n VPN:虚地址的高位(即虚页地址)。在双入口TLB内被称作VPN2,这是为了强调如果每个物理页都是4KB,那么一个虚地址将会去掉低位(这些低位用来选择左边的输出域或右边的输出域)来进行比较以选出一对入口。
n PageMask:这只有近来的CPU才有。它用来控制使用虚地址的多少位来跟VPN进行比较并决定多少位被通过后加入实地址;使用越少的位达成的匹配映射的空间越大。MIPS CPU能够设置一个入口映射最大达16MB的内存。在使用各种页大小的情况下,都是用被掩位中的最高位来选中奇数号或偶数号入口。
n ASID:标记这个转译过程属于某一个特定进程,因此除非CPU的当前ASID与之相吻合,否则匹配是不会成功的。“C”这一位如果被置起为1,则关闭ASID的匹配,这标志着本转译可以在所有的进程空间内进行(因此地址映射中的这一部分是被所有空间共享的),ASID位在早期CPU中为6位长度,而在近期的CPU中则为8位。
TLB的输出部将会给出物理页号和一批数量不大但足够使用的标志位。
n 物理页号(PFN):32位的CPU仅仅有一个N(noncacheable,不可缓存)位——0表示可以缓存,1表示不可缓存。
而64位CPU则提供了一个3位的C域来表示一个更大范围的取值,可以来通知多处理器硬件在访问与其他处理器共享的页面数据时遵循何种协议。不具备硬件上的快存一致性协议特征的64位CPU保留了这样的TLB入口的格式;在所有R4000类型的CPU中只有2个取值来表示可被缓存(3)或者不可缓存(2),后者在R4000类型CPU中为标准默认值。现代的嵌入式CPU可以使用不同的取值来选择不同的快存策略:一对是写透(write through)与写回(write back),另一对为写分配(write allocate)与写不命中的非缓存策略(uncached write on miss)。详情请查阅您的CPU用户手册。
n 写控制位(D):置为1则允许数据写入相应的页。“D”来源于其全称“dirty”;请在6.8节中寻找原因。
n Valid位(V):如果是0,则相应的入口是不可使用(不可用于地址转译)的。看上去好像这没什么意义:既然我们不想转译机制工作,干嘛要把相应的纪录存入TLB呢?这是因为进行重装入动作的软件为了优化速度,不希望去检查特例。当需要在程序能够使用一个内存常驻页表中的页之前对该页进行某些处理时,相应的入口可以先被标记为无效(invalid)。当TLB重装入完成后,这会引发一个不同类型的陷入,调用特殊的程序来进行处理,而不必在每一个重装入事件中都进行测试。
现在转译一个地址就变得很简单了,我们可以把上面所描述的过程充实如下:
n CPU产生一个程序地址:无论是取指令,还是装入和写回数据,只要这些不处于MIPS地址空间中特殊的未映射区间时就会进行转译。
低12位被分离开来,剩下的处于EntryHi的VPN和ASID相拼作为TLB的键值,TLB入口中的PageMask位与C位对这个值有修改效果。
n TLB进行键值匹配:匹配成功的入口被选出。PFN被粘贴在程序地址的低位之前以产生一个完整的物理地址。
n 地址有效吗?V位和D位被参考。如果地址为无效或者正试图写一个D位为0的页,CPU产生一个陷入动作。在所有的转译陷入操作中BadVaddr寄存器都会装入引发陷入的程序地址;而在任何的TLB异常中,TLB的EntryHi寄存器将被预先装入引发陷入的程序地址的VPN。
请不要在TLB不命中处理以外的情况下使用便利寄存器Context(64位CPU中为XContext),在其他时候它们可能用来追踪BadVaddr之类的东西,或者干脆不用,两者都是允许的。
n 是否被缓存?如果C位被置起,那么CPU就到快存中去查找物理地址中的数据拷贝;假如数据不在那里,那么就会到内存中去取并且留一份拷贝到快存中。对于C位未被置起的入口,CPU既不查找快存也不把相应地址的数据装入快存。
当然,TLB的入口数量只能帮助你转译相对较小的程序地址空间——大致在几百KB左右。对大多数系统来说这远远不够,TLB也几乎总是作为一个软件来维护的面向一个更加巨大的转译集合的快存来使用。
当TLB中一次地址查找失败后,会陷入一个TLB重装入异常。系统软件需要做如下工作:
n 判断是否存在一个正确的转译;如果不存在,这个陷入会被派发到用于处理地址错误的程序中去。
n 假如存在一个正确的转译,那么创建一个用于实现转译的TLB入口。
n 假如TLB已经装满(在运行中的系统中它基本上也总是满的),软件要选择一个可以丢弃的入口。
n 软件把新的入口内容填入TLB。