谁执行 TLB 击落?

Who performs the TLB shootdown?

我读到这篇 SO question 描述什么是 TLB 击落。我想了解这是由内核还是处理器或两者执行的操作?

我的问题是:-

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

x86 TLB 不在内核之间共享,并且在硬件级别之间不同步。
是 OS 指示处理器刷新其 TLB。
指示“当前”处理器相当于调用一个函数,指示另一个处理器相当于进行 IPI.

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

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

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

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

执行指令 invlpginvpcid、移动到 cr0cr3(包括在硬件任务切换期间)或 cr4和一个 VMX t运行sition,都使 TLB 无效。
对于确切的 g运行 通用性和语义,请参阅 Intel Manual 3.

的第 4.10.4 节

When exactly does a TLB shootdown happen?

当操作系统或管理程序请求它时发生。

在ISA级别,某些操作可以执行TLB shootdowns(参见Intel手册V3 4.10.4和AMD手册V2 5.5.2),从而使一个或多个本地或远程TLB缓存中的一个或多个TLB条目无效(相同 CPU 的其他逻辑内核和具有 TLB 并共享相同物理内存地址 space 的所有其他类型的处理器)。

另请注意,任何分页结构条目都可以被缓存,即使它没有被任何退役指令访问过。这可能是由于推测执行或 MMU 预取而发生的。因此,一般来说,任何条目都可以随时缓存或失效。当然,有特定的保证可以管理 MMU 缓存并与内存分页结构保持一致。

Who performs the actual TLB shootdown? Is it the kernel(if so, where can I find the code that performs the flushing?) or is it the CPU(if so, what triggers the action) or is it both(the kernel executes an instruction which causes an interrupt, which in turns causes the CPU to perform the TLB shootdown)

正如我之前所说,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。

相关:Do the terms tlb shootdown and tlb flush refer to the same thing.


除了软件启动的 TLB 条目失效,英特尔手册第 3 卷第 4.10.2.2 节针对 P6 微体系结构和大多数后续微体系结构:

Processors need not implement any TLBs. Processors that do implement TLBs may invalidate any TLB entry at any time. Software should not rely on the existence of TLBs or on the retention of TLB entries.

据我所知AMD手册中没有这样的说法。但是也没有给出关于 TLB 整体保留的保证,因此我们可以对 AMD 处理器得出相同的结论。