应用程序数据完整性 (ADI)¶
SPARC M7 处理器增加了应用程序数据完整性(ADI)功能。ADI 允许任务在其地址空间的任意子集上设置版本标签。一旦为任务的地址空间范围启用了 ADI 并设置了版本标签,处理器就会将这些范围内指向内存的指针中的标签与应用程序之前设置的版本进行比较。只有当给定指针中的标签与应用程序设置的标签匹配时,才准许访问内存。如果发生不匹配,处理器会引发异常。
任务要完全启用 ADI,必须采取以下步骤
设置用户模式的 PSTATE.mcde 位。这作为任务整个地址空间的总开关,用于为该任务启用/禁用 ADI。
在与正在启用 ADI 的地址范围相对应的任何 TLB 条目上设置 TTE.mcd 位。MMU 仅在设置了 TTE.mcd 位的页面上检查版本标签。
使用 stxa 指令和特定的 MCD ASI 之一为虚拟地址设置版本标签。每个 stxa 指令为相当于一个 ADI 块大小的字节数设置给定的标签。必须为整个页面重复此步骤,以便为整个页面设置标签。
平台的 ADI 块大小由虚拟机监控程序通过机器描述表提供给内核。虚拟机监控程序还提供虚拟地址中用于指定版本标签的高位位数。一旦为某个内存位置设置了版本标签,该标签就会存储在物理内存中,并且提交给 MMU 的虚拟地址的 ADI 版本标签位中必须存在相同的标签。例如,在 SPARC M7 处理器上,MMU 使用第 63-60 位作为版本标签,ADI 块大小与缓存行大小相同,即 64 字节。如果在一段内存范围上将 ADI 版本设置为(比如)10 的任务,则必须使用第 63-60 位包含 0xa 的虚拟地址来访问该内存。
可以使用带有 PROT_ADI 标志的 mprotect() 在一组页面上启用 ADI。当任务首次在一组页面上启用 ADI 时,内核会为该任务设置 PSTATE.mcde 位。内存地址的版本标签是通过使用 ASI_MCD_PRIMARY 或 ASI_MCD_ST_BLKINIT_PRIMARY 对地址执行 stxa 指令来设置的。ADI 块大小由虚拟机监控程序提供给内核。内核通过辅助向量(auxiliary vector)将 ADI 块大小的值以及其他 ADI 信息返回给用户空间。内核提供以下辅助向量
AT_ADI_BLKSZ
ADI 块大小。这是 ADI 版本控制的粒度和对齐方式,以字节为单位。
AT_ADI_NBITS
VA(虚拟地址)中 ADI 版本位的数量
重要说明¶
版本标签值 0x0 和 0xf 是保留的。这些值与虚拟地址中的任何标签匹配,并且永远不会生成不匹配异常。
尽管标签存储在物理内存中,但版本标签是从用户空间在虚拟地址上设置的。标签是在物理页面分配给任务并为其创建 pte(页表项)之后在物理页面上设置的。
当任务释放设置过版本标签的内存页面时,该页面会返回到空闲页面池中。当此页面重新分配给任务时,内核使用块初始化 ASI 清除该页面,这也同时清除了该页面的版本标签。如果分配给任务的页面被释放并重新分配给同一任务,则该任务先前在该页面上设置的旧版本标签将不再存在。
非故障加载(non-faulting loads)不会检测 ADI 标签不匹配。
内核不会为用户页面设置任何标签,设置任何版本标签完全是任务的责任。如果页面被换出到磁盘并换回,内核确实会确保保留版本标签。如果页面被迁移,它也会保留版本标签。
ADI 适用于任何大小的页面。用户空间任务在使用 ADI 时无需了解页面大小。它只需选择一个虚拟地址范围,使用
mprotect()在该范围上启用 ADI,并为整个范围设置版本标签。mprotect()确保范围与页面大小对齐且是页面大小的整数倍。ADI 标签只能在可写内存上设置。例如,不能在只读映射上设置 ADI 标签。