TLB flush考古、追溯
为什么要刷 TLB?
写在前面,简单说明一些为什么要刷 TLB?能看到这里的小伙伴,大概率是知道什么是 TLB,TLB 就是一块简单的 cache,但是又与 cache 不同,比如一致性。常有 cache coherence(方便描述,后面直接简写成 CC),但是不见有 TLB coherence。最简单来看,支持 CC,我们就理解成硬件会自动同步 cache 中被修改的数据,保证与其他 cache 中的备份数据,以及内存中的数据的一致性。比如 core 0 上的 cache 数据被更新了,硬件会自动失效其他 core 上相同的备份数据。假如 TLB 与 cache 一样,支持 CC,那么如果 core 0 上的 TLB entry 被失效后,硬件会自动失效其他核心上的 TLB entry(这个 CC 看上去,和 Aarch64 上 TLB flush 的硬件实现有点相似)。
回到正题,由于 TLB 并不支持 CC,所以当内存的数据发生变化时,硬件上并不会失效相应的 TLB entry,这些已经过期的 TLB entry,称之为 stale TLB,如果发生读访问,可能会访问到被释放甚至是其他进程的数据,如果发生写操作,轻则进程异常,重则数据丢失。来个严肃的例子,进程A munmap 一段后备是文件的地址(比如表格 A,写全 A),由于某种不知名的原因没有刷 TLB,直接返回,且被切换到其他子线程 B,子线程申请到了刚才虚拟地址写表格 B(写全 B),这个时候可能会出现数据写串的情况,表格 A 里边出现了完全不可能的字母 B...
因此,在修改 PTE 后,且在虚拟地址空间还未再次分配前,尽快刷新 stale TLB,避免 ABA 问题。
最理想的情况,我们清理了一个 PTE,执行一个 TLB flush 指令,硬件会自动取 snoop 相关的 TLB entry 并失效,等下次访问这个...
内存怪谭
写在前面
本系列主要用于记录Linux内核内存BUG相关的故事,以及一些内存奇闻轶事。
shmem - sleep in atomic context
这个BUG在我们龙蜥cloud-kernel的4.19中用stress-ng压测复现。通常情况下,这个BUG对系统稳定性影响并不是很大,仅仅在CONFIG_PREEMPT_COUNT打开的情况下才会,而这个config属于debug类型,一般情况下不会打开。接下来,就分享一下这个怪异的BUG是如何在CONFIG_PREEMPT_COUNT打开的情况下触发的。
首先
#ifdef CONFIG_PREEMPT_COUNT
#define preempt_disable() \
do { \
>-------preempt_count_inc(); \
>-------barrier(); \
} while (0)
#define preempt_enable() \
do { \
>-------barrier(); \
>-------preempt_count_dec(); \... arm64 TLB 硬件设计
TLB flush 硬件行为
arm64 与 x86 在 tlb flush 差异挺大,比如 flush 的范围、同步机制。x86 的 tlb flush 一般是(1)只处理当前核,其他核是否需要刷有操作系统内核去判断,这算是同步机制的范畴,依赖软件发起 IPI 到需要的核,(2)而 arm64 的 TLBI 的范围是整个共享域,以不成熟的经验,arm64 一般只会设计一个共享域,是否其他核也需要同步,是由硬件上去判断。
先从最简单的场景,TLBI 只刷一个核开始。
首先,TLBI 在硬件上并不是一个高优的指令,在执行 TLBI 时,首先会将其存到具有 4 个条目的后台任务队列 STQ 中,等 MMU 主流水线有空闲周期时,开始处理 STQ 队列中的任务。下面是其中一个条目,命名分别是 stq0-stq3:
always_ff @(posedge clk)
begin: u_mm_stq0_type_q_1_0_grp
if (mm_stq0_en == 1\'b1) begin
mm_stq0_type_q[1:0] <= `PERSEUS_DFF_DELAY l2_cpu_snp_type[1:0];
mm_stq0_va_q[`PERSEUS_MMU_VA] <= `PERSEUS_DFF_DELAY l2_cpu_snp_addr[`PERSEUS_MMU_SNP_VA_RANGE];
mm_stq0_va_valid_q <= `PERSEUS_DFF_DELAY l2_cpu_snp_va_valid_ql;...