我读了这个SO question,描述了TLB击落的内容 . 我试图了解这是由内核或处理器执行的操作还是两者兼而有之?
我的问题是: -
-
上下文切换时是否发生TLB击落?我假设不,因为需要能够在多处理器CPU上同时执行多个进程 . 这个假设是否正确?
-
什么时候发生TLB击落?
-
谁执行实际的TLB击落?它是内核(如果是这样,我在哪里可以找到执行刷新的代码?)或者它是CPU(如果是,触发动作的是什么)或是两者(内核执行导致中断的指令,轮流导致CPU执行TLB击球)
我读了这个SO question,描述了TLB击落的内容 . 我试图了解这是由内核或处理器执行的操作还是两者兼而有之?
我的问题是: -
上下文切换时是否发生TLB击落?我假设不,因为需要能够在多处理器CPU上同时执行多个进程 . 这个假设是否正确?
什么时候发生TLB击落?
谁执行实际的TLB击落?它是内核(如果是这样,我在哪里可以找到执行刷新的代码?)或者它是CPU(如果是,触发动作的是什么)或是两者(内核执行导致中断的指令,轮流导致CPU执行TLB击球)
2 回答
x86 TLB不在内核之间共享,在硬件级别之间不同步 .
操作系统指示处理器刷新其TLB .
指示"current"处理器相当于调用一个函数,指示另一个处理器等于IPI .
术语“TLB关闭”明确地指代这种(甚至比正常情况下)昂贵的情况,其中为了保持系统一致性,OS必须告知其他处理器使其TLB无效以便达到特定处理器的相同映射 .
我认为只有在新映射影响某些共享内存时才需要这样做,否则每个处理器都在执行一个进程的不同实例,每个实例都有一个映射 .
在上下文切换期间,刷新TLB以删除旧映射,这必须独立于调度程序运行的最后一个处理器完成 .
由于处理器正在刷新自己的TLB,因此这不是TLB关闭 .
处理器之间必须始终保持一致的共享区域可以是:内核页面,内存映射IO,共享内存映射文件 .
执行指令
invlpg
,invpcid
,移动到cr0
,cr3
(包括在hw任务切换期间)或cr4
以及VMX转换都会使TLB无效 .有关精确的粒度和语义,请参见Intel Manual 3的4.10.4节 .
它可以随时发生,即使操作系统或管理程序没有请求它 . 英特尔手册第3卷第4.10.2.2节明确规定了这一点:
据我所知,AMD手册中没有这样的说法 . 但也没有给出关于TLB entires保留的保证,因此我们可以得出AMD处理器的相同声明 .
因此,总的来说,对这个问题给出一个完整的答案是不可能的 . 但在ISA级别,某些操作可以执行TLB击落(参见英特尔手册V3 4.10.4和AMD手册V2 5.5.2),从而使一个或多个本地或远程TLB缓存中的一个或多个TLB条目无效(其他TLB条目)同一CPU的逻辑核心和具有TLB并共享相同物理内存地址空间的所有其他类型的处理器 .
另请注意,即使任何已退出的指令未访问任何分页结构条目,也可以对其进行高速缓存 . 这可能是由于推测执行或MMU预取而发生的 . 因此,通常,任何条目都可以随时缓存或无效 . 当然,给出了特定的保证,以便可以管理MMU高速缓存并使其与内存中的分页结构保持一致 .
正如我之前所说,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
枚举(评论是我的):在其他情况下,内核会刷新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 .