为什么 ASID 只存在于 ARMv8-A 的 TLB 中?如何避免未经授权访问表中存在但从 TLB 中弹出的内存?

Why are ASID only in the TLB in ARMv8-A? How to avoid unauthorized access to memory present in tables but ejected from TLB?

我有一个关于 ARMv8-A 中的 TLB 和 ASID 的快速问题。
据我了解(来自 ARM 的程序员指南和体系结构参考手册):
- Page/block 描述符(叶 MMU table 条目)不包含 ASID 标识符,仅包含一个 nG(非全局)位,表示 ASID 应该用于此页面。
- 与寄存器值匹配的实际 ASID 值驻留在 TLB 中。它在页面遍历发生时设置,相应的条目被添加到 TLB(使用当前的 ASID,以便后续的 TLB 查找将检查新的 ASID 是否匹配)。

假设我想使用 ASID 来避免在上下文切换时更新 tables。每个进程都有一个驻留的 ASID 值。在 vaddr a1 处处理 1 一些数据,在 vaddr a2 处处理 2。我上下文从 1 切换到 2。在执行期间,对应于 a1 的 TLB 条目被弹出(出于某种原因)。进程 2 访问 a1,发生 TLB 未命中,并且发生页面遍历,成功并使用 ASID2 值存储进程 1 的条目,授予进程 2 访问进程 1 数据的权限

我有什么不明白的? ASID 机制不应该在进程 1 和进程 2 之间提供安全性,同时避免更新 tables 吗?

可选问题:如果我的所有程序在同一虚拟地址处都有 .text 部分(至少,所有程序都具有相同的入口点地址),我是否需要更新 table是时候上下文切换了,还是我可以使用不同的 ASID 匹配同一个 vaddr 的多个条目?

Process 1 some data at vaddr a1, process 2 at vaddr a2. I context switch from 1 to 2. During execution the TLB entry corresponding to a1 gets ejected (for some reason). Process 2 accesses a1, a TLB miss occurs, and a page walk happens, succeeds and stores process 1's entry using ASID2 value, giving process 2 access to process 1's data.

当进程1要访问vaddr a1时,实际上是一个标记为vaddr_a1_with_asid_P1的地址。 Process 2要访问vaddr a1时,其实是一个标记为vaddr_a1_with_asid_P2的地址。 所以在TLB中,每个TLB表项都包含vaddr和进程ASID信息。

那么"Process 2 accesses a1, a TLB miss occurs, and a page walk happens, succeeds and stores process 2's entry using ASID2 value"就不会发生了。

即使是同一个vaddr a1,两个不同的进程访问a1也会产生两个不同的TLB表项。一个标记为ASID P1,另一个标记为ASID P2。

Optional question: if all my programs have .text section at the same virtual address (at least, all programs have the same entry point address), do I need to update tables every time I context switch or can I have several entries matching the same vaddr, using different ASIDs?

Actullay,OS 会处理的。例如,Linux OS 将为进程分配一个唯一的 ASID。对于 8 位或 16 位 ASID 寄存器,总的 ASID 范围是有限的。

所以当所有的ASID都用完后,Linux OS会使整个TLB失效,从0开始重新分配ASID号,作为第二次循环的开始。

看来我对 ASID 有误解。感谢@artlessnoise 的评论,我得到了答案。

在我描述的情况下,我忽略了一个事实,即我们必须在某个时刻映射进程 2 的页面。

所以我们实际做的是:
- 更新 tables:添加进程 2 的页面,并删除进程 2 不能看到的任何页面(包括,在我的示例中,地址为 a1 的页面)
- 更改 ASID,以便任何具有旧 ASID 的缓存值都不能在 TLB
中使用 - 启动进程 2。如果进程 1 的相应页面仍缓存在 TLB 中,则忽略它(因为 ASID 不匹配)。在这两种情况下,都会发生页面遍历,更新后的 table 仅包含进程 2 可访问的页面。

因此,(主要)安全性由进程中存在的 table 提供 2 是 运行。 仅 TLB 中的额外安全性 由 ASID 机制,允许我们不在每个上下文中刷新 TLB 切换。

编辑:另一个(牵强的)解决方案是禁用非缓存页面的页面遍历(改为触发 MMU 故障),并在每次进程访问时手动检查(从内核)进程权限非缓存页面。在性能方面(以及设计方面)似乎很糟糕。

TLB protection using ASID

使用上面的机制可以避免TLB flushing,但是cache entries呢。缓存不会在上下文切换时刷新(当 ASID 位更改时)。缓存都不包含 ASID 位。 例如。

  1. 进程1和进程2都在那里。
  2. 首先进程 1 正在执行,TLB 具有与进程 1 有关的 ASID 位。
  3. 这导致缓存中填充了进程 1 的数据(假设进程 1 根据 PAGE TABLE 使用 pa1 和 pa2 条目填充了缓存)。
  4. 现在有一个上下文切换。
  5. 进程 2 的核心 va 将在 TLB 中具有不同的 ASID 位,因此这将是一个 TLB 未命中并且将有一个页面 table 遍历。
  6. 与进程 2 相关的新 PTE 进入 TLB,因此现在是 TLB 命中。
  7. TLB 命中导致在缓存中搜索数据(其中包含与进程 1 相关但尚未失效或刷新的数据)
  8. 因此可能存在进程 1 的 pa 可能与进程 2 的 pa 重叠的情况,因此即使存在 TLB 保护,进程之间似乎也没有数据保护

--我是不是哪里错了,还是我没有考虑到一些基本的东西,请告诉....

VIPT 缓存中将进行 PA 比较,这对于 VA1 映射到 PA_process_2_with_asid_proc2 的 Process2 将失败。

所以这将是 Process2 访问的缓存未命中。