谁执行TLB击落?

时间:2018-05-09 15:14:08

标签: linux x86 kernel tlb

我读了这篇SO question,描述了TLB击落的内容。我试图了解这是由内核或处理器执行的操作还是两者兼而有之?

我的问题是: -

  1. 上下文切换时是否会发生TLB击落?我假设不,因为需要能够在多处理器CPU上同时执行多个进程。这个假设是否正确?
  2. 究竟是什么时候发生TLB击落?
  3. 谁执行实际的TLB击落?它是内核(如果是这样,我在哪里可以找到执行刷新的代码?)或者它是CPU(如果是,触发动作的是什么)或是两者(内核执行导致中断的指令,轮流导致CPU执行TLB击落)

2 个答案:

答案 0 :(得分:5)

x86 TLB不在内核之间共享,并且在硬件级别之间不同步 操作系统指示处理器刷新其TLB 指示“当前”处理器等于调用函数,指示另一个处理器等于IPI

术语“TLB关闭”明确指的是这种(甚至比正常情况下)昂贵的情况,为了保持系统一致性,操作系统必须告诉其他处理器使其TLB无效以达到特定处理器的相同映射。

我认为只有当新映射影响某些共享内存时才需要这样做,否则每个处理器都在执行一个进程的不同实例,每个实例都有一个映射。

在上下文切换期间,刷新TLB以删除旧映射,这必须独立于预定程序运行的最后一个处理器完成。
由于处理器正在刷新自己的TLB,因此这不是TLB关闭。

处理器之间必须始终保持一致的共享区域可以是:内核页面,内存映射IO,共享内存映射文件。

执行说明invlpginvpcid,转移到cr0cr3(包括在hw任务切换期间)或cr4和VMX转换,都使TLB无效 有关确切的粒度和语义,请参阅Intel Manual 3的第4.10.4节。

答案 1 :(得分:2)

  

什么时候发生TLB击落?

即使操作系统或虚拟机管理程序没有请求它,也可能随时发生。这在英特尔手册第3卷第4.10.2.2节中明确说明:

  

处理器无需实现任何TLB。实现的处理器   TLB可以随时使任何TLB条目无效。软件不应该   依赖于TLB的存在或TLB条目的保留。

据我所知,AMD手册中没有这样的陈述。但也没有给出关于TLB entires保留的保证,因此我们可以为AMD处理器得出相同的声明。

所以一般来说,对这个问题给出一个完整的答案是不可能的。但在ISA级别,某些操作可以执行TLB击落(参见英特尔手册V3 4.10.4和AMD手册V2 5.5.2),从而使一个或多个本地或远程TLB缓存中的一个或多个TLB条目无效(其他TLB条目)同一CPU的逻辑核心和具有TLB并共享相同物理内存地址空间的所有其他类型的处理器。)

另请注意,即使任何已退出的指令未访问任何分页结构条目,也可以对其进行高速缓存。这可能是由于推测执行或MMU预取而发生的。因此,通常,任何条目都可以随时缓存或无效。当然,给出了特定的保证,以便可以管理MMU高速缓存并使其与内存中的分页结构保持一致。

  

谁执行实际的TLB击落?它是内核(如果是的话,在哪里   我可以找到执行刷新的代码吗?)或者它是CPU(如果   所以,是什么触发了动作)或是两者(内核执行一个   导致中断的指令,进而导致CPU   执行TLB击落)

正如我之前所说,CPU本身可以随时使任何条目无效。此外,具有当前特权级别(CPL)= 0的软件可以执行与TLB管理相关的任何操作。

Linux内核中的TLB失效简介

Linux内核定义了与架构无关的TLB失效函数(/arch/x86/mm/tlb.c)和与架构相关的函数(/arch/x86/include/asm/tlbflush.h)。这是因为不同的架构提供了管理TLB的完全不同的机制。要查看Linux内核何时执行TLB失效的一些示例,请参阅tlb_flush_reason枚举(注释是我的):

enum tlb_flush_reason {

    // The memory descriptor structure mm of the current process is about to change.
    // This occurs when switching between threads of different processes.
    // Note that when mm changes, the ASID changes as well (CR3[11:0]).
    // I'd rather not discuss when context switches occur because it's a whole different topic.
    // TLB shootdown only occurs for the current logical core.
    // The kernel sometimes can optimize away TLB flushes on a process-context switch.
    TLB_FLUSH_ON_TASK_SWITCH,

    // Another logical core has sent a request to the current logical core
    // to perform a TLB shootdown on its TLB caches.
    // This occurs due to a KVM hypercall. See TLB_REMOTE_SEND_IPI.
    TLB_REMOTE_SHOOTDOWN,

    // Occurs when one or more pages have been recently unmapped.
    // Affects only the local TLBs.
    TLB_LOCAL_SHOOTDOWN,

    // This occurs when making changes to the paging structures.
    // Affects only the local TLBs.
    TLB_LOCAL_MM_SHOOTDOWN,

    // Occurs when the current logical core uses a KVM hypercall to request
    // from other logical cores to perform TLB shootdowns on their respective TLBs.
    TLB_REMOTE_SEND_IPI,

    // This equals to the number of reasons. Currently not used.
    NR_TLB_FLUSH_REASONS,
};

还有其他情况下内核刷新TLB。很难制作完整的清单,我认为没有人制作过这样的清单。

Linux内核实现了一种懒惰的TLB刷新技术。基本思想是,当修改进程的分页结构时,内核会尝试将TLB击落延迟到该进程中的线程即将被安排在使用模式下执行的时间点。

Linux内核当前使用以下四种方法之一在需要时刷新与当前逻辑核心关联的TLB:

  • 向CR3写入CR3的当前值。虽然这不会改变CR3中的值,但它会指示逻辑核心刷新所有与CR3中的PCID具有相同PCID的非全局TLB条目。
  • 禁用CR4.PGE,然后将CR4的当前值写入CR4,然后重新启用CR4.PGE。这具有刷新所有PCID和全局条目的所有TLB条目的效果。如果支持INVPCID,则不使用此方法。
  • 使用INVPCID指令类型0使给定PCID和虚拟地址的TLB条目无效。
  • 使用INVPCID指令类型2使所有TLB条目无效,包括全局和所有PCID。

目前尚未使用其他类型的INVPCID。