这两天因为某些原因,好好地研究了一下Intel的手册,比较系统地学习了一下和TLB相关的知识。以下内容主要来自Intel手册第三卷的第4章,第11章和第28章。
我们知道,现在内存寻址基本采用的是页表翻译机制,即给定一个虚拟地址,经过2~4层页表,得到一个物理地址。虽然该过程一般由硬件(MMU)完成,但是也会有一定的延迟。因此,为了加速页表翻译的过程,一般的处理器都会有一个翻译信息的缓存机制,在Intel中,有两个相关的机制:TLB
和paging-structure cache
。
TLB,cache的关系如下图所示:
当处理器在获取指令或者读取数据的时候,每当遇到一个虚拟地址,会首先通过TLB等地址翻译缓存机制查找该虚拟地址对应的物理地址,如果没有找到对应的条目,则通过内存翻译硬件机制MMU
通过走页表的方式查找相应的物理地址,当得到确切的物理地址之后,则会通过cache找到物理地址对应的内存数据,如果cache中没有相应的数据,再去内存中读取。
在介绍TLB
和paging-structure cache
之前,有必要先提一下PCID。PCID的全称是Process-Context Identifiers
,如果没有PCID,那么运行在处理器上的软件每次切换CR3,都会造成整个处理器的地址翻译缓存信息(包括TLB
和paging-structure cache
)被刷掉。而PCID则是优化了这一过程。可以这么说,每个进程有自己的一个PCID,这使得进程间的切换不用刷掉处理器中对应的地址翻译缓存信息。
每个进程的PCID由CR3的0:11共12个bits组成,只有在CR4.PCIDE = 1
的情况下才有PCID一说,否则当前的PCID只能是000H
。
当logical processor在TLB
和paging-structure cache
里面创建条目的时候,它会将该条目和当前的PCID挂钩,当翻译地址需要使用这些条目的时候,它也只会查找那些和当前PCID匹配的条目。
注:logical processor的数目一般和processor是一样的,不过当processor支持超线程(hyper-threading)的时候,每个processor上一般会有两个logical processor。
硬件enforce了以下两个关于PCID的规则:
MOV to CR4 causes a general-protection exception (#GP) if it would change CR4.PCIDE from 0 to 1 and either IA32_EFER.LMA = 0 or CR3[11:0] ≠ 000H. MOV to CR0 causes a general-protection exception if it would clear CR0.PG to 0 while CR4.PCIDE = 1.
TLBs的全称是translation lookaside buffers
,它存储了page number
(由虚拟地址的高位组成)到page frame
(由虚拟地址的高位组成)的映射。另外,page number
和page offset
(由虚拟地址的地位组成)的界线由page size
决定:
* 32-bit paging
* * 如果是大页(4M),则`page number`由虚拟地址的31:22位决定;
* * 如果是普通页(4K),则`page number`由虚拟地址的31:12位决定。
* PAE paging
* * 如果是大页(2M),则`page number`由虚拟地址的31:21位决定;
* * 如果是普通页(4K),则`page number`由虚拟地址的31:12位决定。
* IA-32e paging
* * 如果是超大页(1G),则`page number`由虚拟地址的47:30位决定;
* * 如果是大页(2M),则`page number`由虚拟地址的47:21位决定;
* * 如果是普通页(4K),则`page number`由虚拟地址的47:12位决定。
TLB中的每个条目存储了以下信息:
* `page number`所对应的`page frame`;
* 在页表寻址过程中得到的访问权限:
* * The logical-AND of the R/W flags.
* * The logical-AND of the U/S flags.
* * The logical-OR of the XD flags (necessary only if IA32_EFER.NXE = 1).
* 在页表寻址过程中得到的其它属性:
* * The dirty flag
* * The memory type
除了TLB缓存虚拟地址到物理地址的映射之外,还有一个被称为paging-structure cache
的机制,即用于缓存虚拟地址到某一个页表项地址的映射,包括:
* PML4 cache (IA-32e paging only):缓存虚拟地址的47:39位到`PML4E`物理地址的映射;
* PDPTE cache (IA-32e paging only):缓存虚拟地址的47:30位到`PDPTE`物理地址的映射;
* PDE cache:
* * For 32-bit paging,缓存虚拟地址的31:22位到`PDE`物理地址的映射;
* * For PAE paging,缓存虚拟地址的31:21位到`PDE`物理地址的映射;
* * For IA-32e paging,缓存虚拟地址的47:21位到`PDE`物理地址的映射;
除了可以用PCID标记特定的进程的地址翻译缓存信息之外,也可以通过global page的机制标记相应的地址翻译缓存信息。
首先,这需要CR4.PGE设置成1,之后,如果PTE(或者大页的最有一级页表项)中的G bit
(即第8个bit)是1的话,则该TLB条目就被标记成global。需要注意的一点是,
global page这个标记对paging-structure caches
不适用,它只能标记TLB中的条目。
logical processor可以通过被标记成global的TLB条目来翻译一个和当前PCID项不同的虚拟地址。
* 如果在TLB中找到对应虚拟地址到物理地址的映射,则直接使用;
* 否则,在PDE cache中查找,如果有match,则获得相应的PTE的物理地址;
* 否则,在PDPTE cache中查找,如果有match,则获得相应的PDE的物理地址;
* 否则,在PML4 cache中查找,如果有match,则获得相应的PDPTE的物理地址;
* 否则,就直接从CR3中获得PML4的物理地址。
在寻址过程中,只有当四级页表中(对于IA32-e来说)每一个条目的P flag
都是1,且所有的reserved bits
都是0的情况下才会填上相应虚拟地址的TLB条目。paging-structure cache
也类似。另外,在缓存该翻译信息之前,会先把accessed flag
设置为1。
而且,对于prefetch和speculative execution造成的地址翻译也有可能被缓存下来。
另外一点很重要的是,如果软件修改了某一个相应的paging-structure条目,TLB和paging-structure cache里面的条目都可能还存在,这就需要开发者意思到这点,并且能够手动的调用相应的invalidate的指令。
另外还有一个有趣的问题是:Multiple Cached Entries for a Single Paging-Structure Entry,即同一个页表项可能会存在不同的地址翻译缓存,文中给出了两种可能造成该情况的场景:
paging-structure cache
中的条目引用它,因为它们的虚拟地址项是不同的。TLB
和paging-structure cache
引用它。以下操作会invalidate TLB和paging-structure cache相关的条目:
* INVLPG:一个参数:线性地址。该操作会invalidate所有和该线性地址和当前PCID相关的TLB和paging-structure cache条目,以及global TLB条目;
* INVPCID:两个参数:INVPCID type 和 INVPCID descriptor。四种type:
* * Individual-address,即只invalidate一个特定的虚拟地址翻译;
* * Single-context,即只invalidate某个PCID相关的所有的虚拟地址翻译;
* * All-context, including globals,即可以invalidate掉所有PCID对应的虚拟地址翻译,包括global page标记的TLB条目;
* * All-context,同上,但是不能invalidate掉global page标记的TLB条目;
* MOV to CR0:如果将`CR0.PG`从1变成0,将会invalidate所有PCID的`TLB`和`paging-structure cache`的条目,包括global;
* MOV to CR3:
* * 如果`CR4.PCIDE`为0,会invalidate`PCID`为000H的`TLB`和`paging-structure cache`的条目,不包含global;
* * If `CR4.PCIDE`为1,且源地址的第63位为0,将源地址的第11:0位作为PCID,invalidate掉相应PCID的`TLB`和`paging-structure cache`条目;
* * If `CR4.PCIDE`为1,且源地址的第63位为1,则不会invalidate任何条目;
* MOV to CR4:
* * 如果它修改了`CR4.PGE`的值,或者将`CR4.PCID`的值从1改成0,则invalidate所有`TLB`和`paging-structure cache`的条目,包含global;
* * 如果它修改了`CR4.PAE`的值,或者将`CR4.SMEP`的值从0改为1,则invalidate当前PCID的`TLB`和`paging-structure cache`的条目。
* Task switch:如果task switch修改了CR3的值,则将PCID为000H的`TLB`和`paging-structure cache`的条目进行invalidate。
* page fault exception会invalidate和造成page fault相关的虚拟地址所对应的`TLB`和`paging-structure cache`的条目。
在多核环境中,当某个核修改了相应的地址翻译信息需要进行invalidation的时候,也需要考虑其它核的TLB
和paging-structure cache
的缓存了相关的条目。这种地址翻译修改的传递被称为TLB shootdown
,该过程一般是通过memory-based semaphores
或者interprocessor interrupts (IPI)
。文中给了一个低效的实现方案:
* 除了当前的logical processor之外,暂停其它所有的logical processor;
* 让当前的logical processor修改相应的地址翻译信息;
* 让所有的logical processor invalidate相应的`TLB`和`paging-structure cache`条目;
* 恢复所有logical processor的执行。
当然可能会有一些优化的方案,但是需要考虑很多情况,这里就不详细介绍了。
虚拟化环境增加了一层额外的地址翻译,EPT。同时由于在CPU中多了一个root和non-root模式,因此增加了一个virtual processor的概念,相应的,在地址翻译缓存这块也就多增加了一个virtual-processor identifiers(VPID)
的机制进行优化。
在一般情况下,如果发生VMX transition(即vmexit或者vmenter),则会invalidate相应logical processor的TLB,加入了VPID的特性,每个logical processor就可以同时管理多个线性地址空间的TLB,而不需要每次发生VMX transition的时候都invalidate。
VPID在以下三种情况下为000H:
* Outside VMX operation.
* In VMX root operation.
* In VMX non-root operation when the “enable VPID” VM-execution control is 0.
当VMCS的VM-execution control
中enable VPID
被设为1的时候,VMX non-root模式下VPID由当前logical processor中VMCS的VM-execution control
的VPID域来决定。
另外,VPID和PCID是可以同时被使用的。
在EPT被开启的情况下,TLB
和paging-structure cache
中可能会缓存以下信息:
* Guest-physical mappings,包括了`guest-physical page number`到`physical page frame`的映射(存储在`TLB`中),以及guest-physical address的高位到EPT页表页的物理地址的映射(存储在`paging-structure cache`中);
* Combined mappings,包括了`linear page number`到`physical page frame`的映射(存储在`TLB`中),以及`linear page number`到相应页表页的物理地址的映射(存储在`paging-structure cache`中)。
除此之外还有一个叫做linear mapping
,在EPT开启的情况下不会被缓存,它主要映射了线性地址的映射,和非硬件虚拟化的TLB机制类似。
在地址翻译缓存条目的创建和使用过程中,可能会涉及到PCID,VPID和EP4TA(即EPT-PML4-table,表示当前EPTP第51:12位的值)。
在和虚拟化相关的TLB invalidation中,相关的操作如下所示:
linear mappings
和combined mappings
;guest-physical mappings
,以及和该guest-physical address相应的linear address的combined mappings
;enable VPID
位为0,VM entries和VM exits会invalidate掉VPID为0000H的所有linear mappings
和combined mappings
;linear mappings
和combined mappings
。带两个参数:INVVPID type 和 INVVPID descriptor。四种type:guest-physical mappings
和combined mappings
。带两个参数:INVEPT type 和 INVEPT descriptor。两种type: