谁执行TLB击落?

lea*_*arn 3 linux x86 kernel tlb

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

我的问题是: -

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

Had*_*ais 8

TLB 击落究竟何时发生?

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

在 ISA 级别,某些操作可以执行 TLB 击落(参见 Intel 手册 V3 4.10.4 和 AMD 手册 V2 5.5.2),从而使一个或多个本地或远程 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,
};
Run Code Online (Sandbox Code Playgroud)

还有其他情况内核会刷新 TLB。很难列出一个完整的清单,而且我认为没有人做过这样的清单。

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

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

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

当前不使用其他类型的 INVPCID。

相关:术语 tlb shotdown 和 tlb flush 是指同一件事吗


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

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

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

  • 小狡辩:我不会说“[TLB 击落]可能随时发生,即使操作系统或虚拟机管理程序没有请求。” 我将其称为 TLB 失效或缺失,或者可能是 TLB 填充,它获得的值不同于(a)其他 TLB 中相同虚拟地址的 TLB 条目或(b)当前 TLB 在其他时间的转换。// TLB 击落是一个软件构造或算法,仅在硬件手册中提到以展示软件如何做到这一点。至少在您添加 TLB 击落指令之前(例如跨一致性域的 ARMv8.4-A TLBI 广播)。 (2认同)
  • P6 补充说,“软件不应依赖于 TLB 的存在或 TLB 条目的保留”,因为像 P5 这样的早期处理器确实保证了保留,以及最小的 TLB 容量/关联性(没有推测性的 TLB 未命中)。这允许 SW 执行诸如在没有共同虚拟地址的虚拟地址空间之间切换之类的操作(因为保留允许您短暂使用过时的 TLB 条目),而由于 P6 SW 这样做是“鼓励”至少拥有一页,因此映射执行 CR3 的代码发生变化,身份映射到新旧虚拟地址空间。// 让我有点难过。 (2认同)

Mar*_*oom 5

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

术语"TLB关闭"明确地指代这种(甚至比正常情况下)昂贵的情况,其中为了保持系统一致性,OS必须告知其他处理器使其TLB无效以便达到特定处理器的相同映射.

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

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

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

的指令的执行invlpg,invpcid,此举cr0,cr3(包括HW任务切换过程中)或cr4与一个VMX过渡,所有无效TLB.
有关确切的粒度和语义,请参阅" 英特尔手册3"的第4.10.4节.