news 2026/8/7 23:01:33

Linux 内存管理:TLB ASID

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux 内存管理:TLB ASID

文章目录

  • 1. 前言
  • 2. TLB ASID 的硬件支持
    • 2.1 概念
    • 2.2 TLB 查找
  • 3. Linux 下 TLB ASID 管理
  • 4. 参考资料

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. TLB ASID 的硬件支持

2.1 概念

  • 什么是TLB
    TLBTranslation Lookaside Buffers的缩写,MMU 将虚拟地址(VA)翻译为物理地址(PA)时,要经过页表遍历(page table walk)过程,每访问一级页表就要一次内存访问,相对来说,这个延迟还是相对较大的。为了提高性能,硬件上引入了 TLB cache 缓存,首次访问一个 VA 后,将 MMU 转换的 PA 以对应的 VA 为 tag 缓存到 TLB 缓存,下次再访问同一 VA,就可以通过以 VA 为 tag 从 TLB 搜索提取对应的 TLB entry 了,不用再经历漫长的page table walk过程。当然,TLB 的容量有限,只能缓存有限个数 VA 翻译的 PA 地址,这就需要做一定的管理,在 TLB 耗尽时,通过某种算法,用新的 PA 将一些旧的缓存替换掉。

  • 什么是 TLB ASID?
    ASIDAddress Space Identifier的缩写,标识属于特定进程的TLB entries。那为什么需要它?前面说过,TLB 容量有限,在系统中属于珍贵资源;另外,在系统进程的切换过程中,会进行页表切换,而每个进程的页表不一样,那意味着,当前进程的 TLB 缓存的地址翻译内容,对新进程将失效,所以页表切换需要进行整个 TLB cache 的 flush,这会带来不小的性能损失。于是硬件上引入了nG(not Global)标志位 和ASID,来对该问题进行优化:nG=0标识 TLB entries 属于 ASID 标识的进程,nG=1标识 TLB entries 属于全局的内核空间地址(所有进程共享内核空间的页表映射)。这样,在切换进程的页表时候,只需要为新进程分配一个 ASID 来标识自己的 TLB entries,在 ASID 或 TLB cache entries 消耗完之前,都不需要刷 TLB cache 了。

2.2 TLB 查找

nG标志位同时位于最后一级页表的表项TLB entries中,然后首次内存访问某个地址时,记录到 TLB entries 中。而当前进程的ASID,会在进程页表切换时设置到TTBRx寄存器中,同时也会在首次访问某个VA地址时,记录到TLB entries中。当然,TLB entries 也记录访问VA地址的VA tag。这样,在后续访问某一VA地址时,首先比较 VA 地址 TLB entries VA tag,如果不匹配,则表示 TLB miss,要继续进行page table walk来翻译PA;如果相同,则继续查看 TLB entry 的nG位,如果为nG=0,则意味着是内核空间地址的 TLB entry,所有进程共享,即命中了 TLB,返回 TLB entry 保存的PA即可;如果nG=1,则表示是某进程特定的 TLB entry,通过 ASID 标识,则继续比较 TLB entry 的 ASID 和 TTBRx 寄存器存储的当前进程的 ASID,如果值相同,则标识命中,否则标识 TLB miss,否则要继续进行page table walk来翻译PA

3. Linux 下 TLB ASID 管理

ARMv7架构 +Linux 4.14.x内核简略的分析下TLB ASID的管理细节,来看代码:

typedefstruct{#ifdefCONFIG_CPU_HAS_ASIDatomic64_tid;/* ASID: generation | HW ASID */#else...#endif...}mm_context_t;
voidcheck_and_switch_context(structmm_struct*mm,structtask_struct*tsk){unsignedlongflags;unsignedintcpu=smp_processor_id();u64 asid;...asid=atomic64_read(&mm->context.id);/* 读取新进程的 ASID *//* * a. !((asid ^ atomic64_read(&asid_generation)) >> ASID_BITS * 新进程 asid 属于/分配自 当前 generation * b. atomic64_xchg(&per_cpu(active_asids, cpu), asid) * a.成立的条件下, 顺便设定 当前 CPU 激活的 (进程的) asid, * 然后就可以进入页表的切换过程了. */if(!((asid^atomic64_read(&asid_generation))>>ASID_BITS)&&atomic64_xchg(&per_cpu(active_asids,cpu),asid))gotoswitch_mm_fastpath;/* ASID 无需更新,直接进入页表切换过程 */raw_spin_lock_irqsave(&cpu_asid_lock,flags);/* Check that our ASID belongs to the current generation. */asid=atomic64_read(&mm->context.id);/* 新进程 asid 不 属于/分配自 当前 generation, 要重新从当前 generation 为新进程分配 asid */if((asid^atomic64_read(&asid_generation))>>ASID_BITS){asid=new_context(mm,cpu);/* ASID 管理操作 */atomic64_set(&mm->context.id,asid);/* 为 进程 分配的 ASID 记录到 进程的 mm_struct */}/* 当前 generation ASID 耗尽,需要刷掉所有的 TLB cache */if(cpumask_test_and_clear_cpu(cpu,&tlb_flush_pending)){local_flush_bp_all();local_flush_tlb_all();}atomic64_set(&per_cpu(active_asids,cpu),asid);/* 当前 CPU 激活的 (进程的) asid */cpumask_set_cpu(cpu,mm_cpumask(mm));raw_spin_unlock_irqrestore(&cpu_asid_lock,flags);}staticu64new_context(structmm_struct*mm,unsignedintcpu){staticu32 cur_idx=1;u64 asid=atomic64_read(&mm->context.id);u64 generation=atomic64_read(&asid_generation);/* * 在创建新的进程的时候会分配一个新的 mm, 其(mm->context.id)初始化为 0. * 如果 asid 不等于 0, 那么说明这个 mm 之前就已经分配过 software asid * (generation + hw asid)了. */if(asid!=0){u64 newasid=generation|(asid&~ASID_MASK);/* * If our current ASID was active during a rollover, we * can continue to use it and this was just a false alarm. */if(check_update_reserved_asid(asid,newasid))returnnewasid;/* * We had a valid ASID in a previous life, so try to re-use * it if possible., *//* 如果新 generation 中旧的 asid 还未被分配出去, 重用它 */asid&=~ASID_MASK;if(!__test_and_set_bit(asid,asid_map))returnnewasid;/* 返回更新了 generation 的 asid */}/* * 如果 asid 等于 0, 说明我们的确是需要分配一个新的 HW asid, * 这时候首先要找一个空闲的 HW asid, 如果能够找到, 那么直接返 * 回 software asid (当前 generation + 新分配的 hw asid); 否则, * 表示 asid 消耗完了,生成新的 generation 并重新进行分配??? */asid=find_next_zero_bit(asid_map,NUM_USER_ASIDS,cur_idx);if(asid==NUM_USER_ASIDS){/* ASID 消耗完了,需重新分配 */generation=atomic64_add_return(ASID_FIRST_VERSION,&asid_generation);/* 递增 ASID generation */flush_context(cpu);asid=find_next_zero_bit(asid_map,NUM_USER_ASIDS,1);}__set_bit(asid,asid_map);/* 更新 ASID 分配位图: 标记 asid 已经被分配 */cur_idx=asid;cpumask_clear(mm_cpumask(mm));returnasid|generation;/* 返回新分配的 asid */}staticvoidflush_context(unsignedintcpu){inti;u64 asid;/* Update the list of reserved ASIDs and the ASID bitmap. */bitmap_clear(asid_map,0,NUM_USER_ASIDS);for_each_possible_cpu(i){asid=atomic64_xchg(&per_cpu(active_asids,i),0);/* * If this CPU has already been through a * rollover, but hasn't run another task in * the meantime, we must preserve its reserved * ASID, as this is the only trace we have of * the process it is still running. */if(asid==0)asid=per_cpu(reserved_asids,i);__set_bit(asid&~ASID_MASK,asid_map);per_cpu(reserved_asids,i)=asid;}/* Queue a TLB invalidate and flush the I-cache if necessary. */cpumask_setall(&tlb_flush_pending);/* 当前 generation 的 asid 耗尽, 更新 generation, 标记要刷 TLB */if(icache_is_vivt_asid_tagged())__flush_icache_all();}

4. 参考资料

[1] DDI0406C_d_armv7ar_arm.pdf
[2] TLB原理

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/7 18:08:41

Xiaomi 商城页面布局(部分)

HTML部分&#xff1a;<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><li…

作者头像 李华
网站建设 2026/8/7 19:17:00

运料小车装卸料控制:西门子1200PLC与TP700触摸屏联机仿真博途16

运料小车装卸料控制西门子1200PLC和TP700触摸屏联机仿真博途16最近在车间折腾运料小车的自动化改造&#xff0c;用西门子1200PLC搭了个装卸料控制系统。正好手头有TP700触摸屏&#xff0c;索性在博途V16里搞了个联合仿真&#xff0c;省得去现场调试吃灰。这个方案特别适合产线还…

作者头像 李华
网站建设 2026/8/6 19:49:50

S32K311启动过程中,向量表重定向

在MCU的启动过程中&#xff0c;NXP官方提供的启动代码会对中断向量表进行重定向&#xff0c;将向量表从flash定向到ram。具体实现分析如下。Vector_Table.sSECTION .intvec:DATA:ROOT(2&#xff09;通过这个命令&#xff0c;声明一个.intvec的段&#xff0c;这条指令下面申明的…

作者头像 李华
网站建设 2026/8/7 8:10:16

从蓝图到产线:高效产品信息传递的桥梁建设

在制造业中&#xff0c;研发设计的精妙构思与生产部门的高效执行之间&#xff0c;存在着一条至关重要的信息传递链。这条链路的畅通与否&#xff0c;直接决定了产品能否从图纸精准、准时地转化为合格的商品。本文将深入探讨这一过程的标准实践、常用工具、潜在挑战及其优化方案…

作者头像 李华
网站建设 2026/8/4 14:29:39

时间复杂度

这种题目是数据结构与算法考研&#xff08;如408&#xff09;或面试中的高频送分题&#xff0c;但也是高频陷阱题。 复习这类题目&#xff0c;不要靠“猜”或者“死记硬背”&#xff0c;而是要掌握一套**“数学建模”**的方法。一旦你建立了数学直觉&#xff0c;这类题看一眼就…

作者头像 李华