IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    TLB的那些事儿

    Liu Yutao发表于 2016-09-16 09:39:00
    love 0

    这两天因为某些原因,好好地研究了一下Intel的手册,比较系统地学习了一下和TLB相关的知识。以下内容主要来自Intel手册第三卷的第4章,第11章和第28章。

    我们知道,现在内存寻址基本采用的是页表翻译机制,即给定一个虚拟地址,经过2~4层页表,得到一个物理地址。虽然该过程一般由硬件(MMU)完成,但是也会有一定的延迟。因此,为了加速页表翻译的过程,一般的处理器都会有一个翻译信息的缓存机制,在Intel中,有两个相关的机制:TLB和paging-structure cache。

    TLB,cache的关系如下图所示:

    i7

    当处理器在获取指令或者读取数据的时候,每当遇到一个虚拟地址,会首先通过TLB等地址翻译缓存机制查找该虚拟地址对应的物理地址,如果没有找到对应的条目,则通过内存翻译硬件机制MMU通过走页表的方式查找相应的物理地址,当得到确切的物理地址之后,则会通过cache找到物理地址对应的内存数据,如果cache中没有相应的数据,再去内存中读取。

    PCID

    在介绍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.

    TLB

    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
    

    Paging-Structure Caches

    除了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`物理地址的映射;
    

    Global Pages

    除了可以用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,即同一个页表项可能会存在不同的地址翻译缓存,文中给出了两种可能造成该情况的场景:

    • 假设两个PML4E指向了同一个PDPT,因此对于这个PDPT中的任意一个PDPTE,都有可能会有两个paging-structure cache中的条目引用它,因为它们的虚拟地址项是不同的。
    • 假设某个PML4E指向了PML4本身,这样,所有47:39位为0,或者47:30为0,或者47:21为0,以及47:12为0的这些虚拟地址都是指向PML4的物理地址,因此,PML4的物理地址就可能会有很多的TLB和paging-structure cache引用它。

    TLBs and Paging-Structure Caches的invalidate机制

    以下操作会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中,相关的操作如下所示:

    • 和VMX不相关的invalidation指令(如INVLPG和INVPCID),会invalidate当前VPID的linear mappings和combined mappings;
    • EPT violation会invalidate当前EP4TA相关的guest-physical mappings,以及和该guest-physical address相应的linear address的combined mappings;
    • 如果enable VPID位为0,VM entries和VM exits会invalidate掉VPID为0000H的所有linear mappings和combined mappings;
    • INVVPID指令,会invalidate掉linear mappings和combined mappings。带两个参数:INVVPID type 和 INVVPID descriptor。四种type:
      • Individual-address,即只invalidate一个特定的虚拟地址翻译;
      • Single-context,即只invalidate某个VPID相关的所有的虚拟地址翻译;
      • All-context,即可以invalidate掉所有VPID(除了000H)对应的虚拟地址翻译;
      • Single-context-retaining-globals,同single-context,但是不能invalidate掉global page标记的TLB条目;
    • INVEPT指令,会invalidate掉guest-physical mappings和combined mappings。带两个参数:INVEPT type 和 INVEPT descriptor。两种type:
      • Single-context,即只invalidate某个EP4TA相关的所有的虚拟地址翻译;
      • All-context,即可以invalidate所有EP4TA相关的所有的虚拟地址翻译;


沪ICP备19023445号-2号
友情链接