时间轴

2025-10-26

init

参考文档:

TLB基础知识

  • ARMv8.6 芯片手册与TLB相关内容

    • D5.9章 Translation Lookaside Buffers(TLBs)

    • D5.10章 TLB maintenance requirements and the TLB maintenance instructions

TLB背景知识

TLB

  • TLB是cache的一种
  • TLB的表项:记录了最新使用的VA到PA的转换结果
  • TLB基地址在映射基础寄存器(TTBR0_EL1)和(TTBR1_EL1)中指定。当 VA 的上面几位都是 0 时,TTBR0
    所指向的映射表被选中,当 VA 的上面几位都被设置为 1 时,TTBR1 被选中。
  • EL2 和 EL3 有一个 TTBR0,但没有 TTBR1。这意味着:
    • 如果 EL2 使用的是 AArch64,它只能使用范围在 0x0 到 0x0000FFFF_FFFFFFFF。
    • 如果 EL3 使用的是 AArch64,它只能使用范围在 0x0 到 0x0000FFFF_FFFFFFFF。

TTBR0_EL1和TTBR1_EL1

  • TLB也支持全相连,支持直接映射,组相连等三种映射方式。
  • Cortex-A72采用两级TLB设计。类似2级cache的设计思路。
    • L1 instruction and data TLBs(全相连)
      • 48-entry fully-assocaitive L1 1-TLB
      • 32-entry fully-associative L1 D-TLB
    • L2 unified TLB.4-way set-associative of 1024-entry L2 TLB(组相连)

组相联TLB

每个 TLB 条目通常不仅包含物理地址和虚拟地址,还包含诸如内存类型、缓存策略、访问权限、地址空间 ID
(ASID)和虚拟机 ID(VMID)等属性

使用TLBde

TLB的重名(别名)问题

TLB的重名问题

虽然VP1和VP2在TLB里缓存了两个不同的TLB entry,但是TLB entry里的PFN都是指向Phys Page,所以,不会产生别名问题

TLB的同名问题

相同虚拟地址映射不同物理地址

进程A切换到进程B,旧进程使用的TLB对新进程来说是无用数据,并且可能产生同名问题。如果直接在进程切换时invalidate TLB,那么性能上会有较大损失。解决方法就是使用ASID(Address Space Identifier)技术

ASID(Address Space Identifier)

  • 全局类型的TLB内核空间是所有进程共享的空间
  • 进程独有类型的TLB:用户地址空间是每个进程独立的地址空间
  • ASID机制用来实现进程独有类型的TLB
  • ARMv8的ASID是存储在TTBR0_EL1或者TTBR1_EL1中。其中TCR寄存器的A1域可以做选择
  • ASID支持8位或者16位
    • 8位宽的ASID,最多支持256个ID
    • 16位宽的ASID,支持65536个ID

ASID

TCR_El1.A1 filed selects TTBR0_EL1.ASID or TTBR1_EL1.ASID

TCR_EL1 中定义:

TCR_EL1.A1

TLB可以识别哪个TLB entry属于哪个进程,这个是解决TLB同名问题的核心思想。这样进程切换时只需要刷掉被切换的进程的TLB entry

操作系统常使用位图的方式管理ASID,一般不会用进程的PID

通过ASID来查找进程特有的TLB表项

此外,ARMv8-A 架构提供线程 ID 寄存器供操作系统软件使用。这些寄存器没有硬件意义,通常由线程库作
为每个线程数据的基本指针使用。这通常被称为线程本地存储(TLS)。例如,pthreads 库使用这一功能,包
括以下寄存器:

  • 用户读写线程 ID 寄存器(TPIDR_EL0)。
  • 用户只读线程 ID 寄存器(TPIDRRO_EL0)。
  • 线程 ID 寄存器,仅限特权访问(TPIDR_EL1)

Linux内核里的ASID

  • Linux内核里为每个进程分配两个ASID,即奇,偶数组成一对

    • 当进程运行在用户态时,使用奇数ASID来查询TLB
    • 当程序陷入内核态运行时,使用偶数ASID来查询TLB

    为每个进程分配两个ASID主要是解决熔断漏洞问题

  • 硬件的ASID的分配通过位图来分配和管理

  • 进程切换的时候,需要把进程持有的硬件ASID写入到TTBR1_EL1寄存器里

  • 当系统中所有的硬件ASID加起来超过硬件最大值时会发生溢出,需要刷新全部TLB,然后重新分配硬件ASID

Linux内核的ASID

页表项中的nG属性

页表项中的nG属性

第11位nG:

  • 1:表示这个页面对应的TLB页表项是进程特有的

  • 0:表示是使用全局的TLB

TLB缓存一个块

ARMv8-A 架构提供了一个称为连续块条目的功能,以有效地使用 TLB 空间。

映射表块条目每个都包含一个连续的位。当设置时,该位向 TLB 发出信号,它可以缓存一个涵盖多个块的映射的单一条目。一个查找可以索引到一个连续块所覆盖的地址范围的任何地方。因此,TLB 可以为定义的地址范围缓存一个条目,使得在 TLB 中存储更大范围的虚拟地址成为可能。

要使用一个连续的位,连续的块必须是相邻的,也就是说它们必须对应于一个连续的虚拟地址范围。它们必须从一个对齐的边界开始,具有一致的属性,并指向同一级别转换的连续输出地址范围。

TLBI指令

如果操作系统修改了可能已缓存在 TLB 中的映射条目,那么操作系统就有责任使这些陈旧的 TLB 条目失效,需要使用TLBI指令

  • ARMv8提供了TLBI指令
  • 指令格式:
1
TLBI <type><level>{IS} {,Xt}
  • Type:
    • ALL 整个TLB
    • VMALL 所有的TLB entry(stage 1, for current guest OS)
    • VMALLS12 所有的TLB entry(stage 1&2 for current guest OS)
    • ASID 和ASID匹配的TLB entry,xt指定虚拟地址以及ASID
    • VA 虚拟地址指定的TLB entry,xt指定虚拟地址以及ASID
    • VAA 虚拟地址指定的TLB entry,xt制定了虚拟地址但是不包括ASID
  • Level:En=异常等级(n可以是3,2,or 1)
  • IS:表示inner share
  • Xt:由虚拟地址和ASID组成的参数
    • Bit[63:48]:ASID
    • Bit[47:44]:TTL,用于指明使哪一级的页表保存的地址无效。若为0,表示需要使所有级别的页表无效(一般都设置为0)
    • Bit[43:0] :虚拟地址的Bit[55:12]

TLBI指令的操作符

例子:修改页表后对TLB进行刷新

1
2
3
4
5
// Writes to Translation Tables
DSB ISHST // ensure write has completed
TLBI ALLE1 // invalidate all TLB entries
DSB ISH // ensure completion of TLB invalidation
ISB // synchronize context so no old translations are used

执行场景:你修改了页表映射(如修改虚拟地址到物理地址的映射),CPU 仍可能用旧 TLB 翻译缓存,所以:

  1. 必须先确保页表写入完成DSB ISHST
  2. 使旧 TLB 失效TLBI ALLE1
  3. 确保失效动作真正完成DSB ISH
  4. 刷新 CPU 指令执行上下文ISB

相关寄存器

TCR_EL1

TCR_EL1 控制 EL1 和 EL0 的其他内存管理功能。

TCR_EL1寄存器

Bit assignment

TCR_EL1

字段 位范围 含义 用于
T0SZ [5:0] 控制 TTBR0 的虚拟地址空间大小 用户空间或低地址映射
TG0 [15:14] TTBR0 页大小(Granule Size) 4KB/16KB/64KB 页
T1SZ [21:16] 控制 TTBR1 的虚拟地址空间大小 内核空间或高地址映射
TG1 [31:30] TTBR1 页大小(Granule Size) 4KB/16KB/64KB 页
IPA size [34:32] 控制中间物理地址宽度 (Intermediate Physical Address Size) 用于虚拟化或物理地址上限设置