谁执行TLB shootdown?

10
我阅读了这篇描述TLB shootdown是什么的SO问题。我想知道这是由内核还是处理器执行的操作,或者两者都有?
我的问题如下:
1.在上下文切换时是否会发生TLB shootdown?我认为不会,因为需要在多处理器CPU上同时执行多个进程。这个假设正确吗?
2.TLB shootdown确切发生的时间是什么时候?
3.谁执行实际的TLB shootdown?是内核(如果是,我在哪里可以找到执行清除的代码?)还是CPU(如果是,是什么触发了这个动作),还是两者都执行(内核执行导致中断的指令,从而使CPU执行TLB shootdown)?
2个回答

14

x86 TLB不在核心之间共享,也没有在硬件级别上进行同步。
是操作系统指示处理器刷新其TLB。指示当前处理器相当于调用函数,指示另一处理器相当于发出IPI

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

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

在上下文切换期间,TLB被刷新以删除旧映射,这必须独立于计划运行最后一个处理器。既然处理器正在刷新自己的TLB,这不是TLB shootdown。

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

执行指令invlpginvpcid、移动到cr0cr3(包括在硬件任务切换期间)或cr4和VMX转换,都会使TLB失效。关于确切的粒度和语义,请参见Intel Manual 3的第4.10.4节。

10

TLB shootdown是在什么时候发生的?

它发生在操作系统或超级监视程序请求时。

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

还要注意,即使任何未使用过的分页结构条目,都可能被缓存。这可能是由于推测执行或MMU预取而发生的。因此,通常情况下,任何条目都可以随时被缓存或失效。当然,有特定的保证,以便可以管理MMU缓存,并使其与内存分页结构保持一致。

实际的TLB shootdown是由谁执行的?是内核吗?(如果是,则在哪里可以找到执行刷新的代码?)还是CPU?(如果是,则是什么触发了该操作?)还是两者兼备?(内核执行导致中断的指令,进而导致CPU执行TLB shootdown)

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

Linux内核中关于TLB失效的介绍

Linux内核定义了架构相关的TLB无效函数(/arch/x86/mm/tlb.c)和架构相关的函数(/arch/x86/include/asm/tlbflush.h)。这是因为不同的体系结构提供了完全不同的机制来管理TLBs。要查看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 shootdowns到该进程的线程即将被调度执行使用模式的时候。
当需要时,Linux内核目前使用以下四种方法之一来刷新与当前逻辑核心相关联的TLB:
1. 向CR3写入CR3的当前值。虽然这不会改变CR3中的值,但它指示逻辑核心刷新所有具有与CR3中相同PCID的非全局TLB条目。 2. 禁用CR4.PGE,然后写入CR4的当前值,然后重新启用CR4.PGE。这将导致刷新所有PCID和全局条目的所有TLB条目。如果支持INVPCID,则不使用此方法。 3. 使用INVPCID指令类型0使给定PCID和虚拟地址的TLB条目无效。 4. 使用INVPCID指令类型2使包括全局和所有PCID的所有TLB条目无效。
目前不使用其他类型的INVPCID。
相关:tlb shootdown和tlb flush是指相同的事情吗
除了软件发起的TLB条目无效之外,Intel手册第3卷第4.10.2.2节适用于P6微架构和大多数后续微架构:
处理器不需要实现任何TLB。实现TLB的处理器可以在任何时候使任何TLB条目无效。软件不应依赖于TLB的存在或保留TLB条目。
据我所知,AMD手册中没有这样的声明。但是也没有关于TLB条目保留的保证,因此我们可以得出相同的结论适用于AMD处理器。

1
/arch/x86/mm/tlb.c和/arch/x86/include/asm/tlbflush.h都是x86特定的。我不知道为什么你把/arch/x86/mm/tlb.c作为“与体系结构无关”的代码示例。 - Wojciech Kudla
2
小问题:我不会说“[TLB shootdown]可以在任何时候发生,即使操作系统或虚拟机监视器没有请求。” 我会称之为TLB失效或未命中,或者可能是TLB填充,其值与其他TLB中相同虚拟地址的(a)TLB条目或(b)当前TLB中的翻译在其他时间不同。 // TLB shootdown是一个软件构造或算法,只在硬件手册中提到,以展示软件如何执行它。至少在添加TLB shootdown指令之前是这样(例如ARMv8.4-A TLBI跨一致性域广播)。 - Krazy Glew
2
P6添加了“软件不应该依赖于TLB的存在或保留TLB条目”,因为早期的处理器如P5确保了保留,并具有最小的TLB容量/关联性(没有推测性的TLB未命中)。这使得软件可以执行诸如在没有共同虚拟地址的虚拟地址空间之间切换的操作(因为保留允许您短暂使用过时的TLB条目),而自从P6以来,建议软件至少有一个页面,将执行CR3更改的代码映射到旧和新的虚拟地址空间中的身份映射。// 这让我有点难过。 - Krazy Glew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接