ARM架构中的数据缓存清理与无效化操作
DC CIVAC 是ARM架构中的一条系统指令,全称是 Data or unified Cache line Clean and Invalidate by VA to PoC。
简单来说,它的作用是:
DC CIVAC 是一条系统指令,需要在特权模式下执行(通常是EL1或更高权限级别)。
| op0 | op1 | CRn | CRm | op2 |
|---|---|---|---|---|
| 0b01 | 0b011 | 0b0111 | 0b1110 | 0b001 |
DC CIVAC, <Xt>
其中 <Xt> 是一个64位通用寄存器,包含要操作的虚拟地址。
// 假设x0寄存器中包含要操作的虚拟地址 DC CIVAC, x0
注意:在用户模式(EL0)下执行此指令可能会产生权限错误,除非系统明确允许。
DC CIVAC 指令在以下场景中非常有用:
当设备通过DMA直接访问内存时,需要确保缓存中的数据已经写回内存:
// 在DMA读取之前:清理缓存,确保设备获取最新数据 DC CIVAC, x0 // 启动DMA读取操作
当程序修改自身的代码时,需要确保指令缓存与数据缓存的一致性:
// 修改代码段 str x1, [x0] // 将新指令写入内存 DC CIVAC, x0 // 清理数据缓存 IC IVAU, x0 // 无效化指令缓存 isb // 确保所有操作完成
在多核系统中,当一个核心修改了共享数据,需要通知其他核心:
// 核心1修改共享数据 str x1, [x0] // 修改数据 DC CIVAC, x0 // 清理并使缓存行无效 sev // 发送事件,唤醒其他核心
在Linux内核中,DC CIVAC常用于维护缓存一致性:
// arch/arm64/mm/cache.S
ENTRY(__flush_dcache_area)
// x0: 虚拟地址起始位置
// x1: 区域大小
add x1, x0, x1
sub x1, x1, #1
bic x0, x0, #(1 << 4) - 1
1:
dc civac, x0 // 清理并使缓存行无效
add x0, x0, #(1 << 4)
cmp x0, x1
b.lo 1b
dsb sy
ret
ENDPROC(__flush_dcache_area)
在安全启动过程中,ATF使用DC CIVAC确保安全数据的一致性:
// lib/aarch64/cache_helpers.S
func flush_dcache_range
// x0: 虚拟地址起始位置
// x1: 虚拟地址结束位置
mrs x2, ctr_el0
ubfx x2, x2, #16, #4
mov x3, #4
lsl x3, x3, x2
sub x4, x3, #1
bic x0, x0, x4
1:
dc civac, x0 // 清理并使缓存行无效
add x0, x0, x3
cmp x0, x1
b.lo 1b
dsb sy
ret
endfunc flush_dcache_range
在安全环境中,OP-TEE使用DC CIVAC保护安全数据:
// core/arch/arm/kernel/cache_helpers_a64.S
LOCAL_FUNC cache_op_inner_dccivac , :
// x0: 虚拟地址
// x1: 大小
add x1, x0, x1
sub x1, x1, #1
bic x0, x0, #CACHELINE_MASK
1:
dc civac, x0 // 清理并使缓存行无效
add x0, x0, #CACHELINE_SIZE
cmp x0, x1
b.lo 1b
dsb sy
ret
END_FUNC cache_op_inner_dccivac
DC CIVAC指令的执行受到系统权限控制:
提示:在编写系统代码时,需要仔细考虑缓存操作的正确性和性能影响,不必要的缓存操作会显著降低系统性能。