ARM 架构中的数据同步屏障(DSB)是什么?
在 ARM 架构中,数据同步屏障(DSB,Data Synchronization Barrier) 是一种内存屏障(Memory Barrier) 指令,用于确保在屏障之前的所有内存访问操作 (包括加载、存储、以及某些系统寄存器访问)都已经在内存系统中完成,然后才能执行屏障之后的指令或操作。
DSB 的核心作用
简单来说,DSB 会强制处理器等待,直到满足以下条件:
- 在 DSB 之前发出的所有显式内存访问(如
LDR/STR)都已完成。 - 这些访问的效果对于指令所指定的共享域 (Shareability domain)内的所有观察者(如其他 CPU 核心、DMA 设备、GPU 等)都可见且已完成。
这意味着,在 DSB 后面的指令不会开始执行,直到 DSB 前面的内存访问在内存系统中彻底完成。
DSB 与相关指令的区别
ARM 中有几种常见的内存屏障指令:
| 指令 | 全称 | 作用 |
|---|---|---|
| DMB | Data Memory Barrier | 确保内存访问的顺序,但不保证完成时间。主要用于多核/设备间的数据依赖顺序。 |
| DSB | Data Synchronization Barrier | 比 DMB 更强,确保内存访问完成并同步,且会暂停后续指令执行直到内存访问完成。 |
| ISB | Instruction Synchronization Barrier | 清空处理器流水线,确保后续指令从内存重新读取(用于代码修改、系统控制寄存器更新后)。 |
简单比喻:
- DMB 像交通警察,让两个方向的车按顺序通过,但不保证车已经到达目的地。
- DSB 则要求所有车必须到达目的地并确认,后面的车才能出发。
- ISB 则是要求所有司机刷新导航(指令缓存),确保看到新路线。
DSB 的典型使用场景
-
对内存映射的 I/O 寄存器进行写操作后
例如,向一个设备寄存器写入控制命令,需要确保这个写入操作确实到达设备,才能进行下一步(如读取设备状态)。否则可能因为写缓冲(Write Buffer)延迟导致设备未收到命令。
-
修改页表或内存属性后
在改变 MMU 配置(如修改地址翻译表)后,需要执行 DSB 确保之前的内存访问已完成,然后再更新系统寄存器(如 TTBR),最后可能还需要 ISB。
-
自我修改代码(Self-modifying code)
在写入新的指令到内存后,需要 DSB 确保写入完成,然后可能清除指令缓存,最后用 ISB 确保后续执行新指令。
-
异常入口/出口或上下文切换
在切换地址空间或修改系统寄存器前,可能需要 DSB 来确保之前的内存访问在系统中可见。
DSB 的语法(ARM 汇编)
assembly
DSB <option>
其中 <option> 指定了屏障的作用域,常见的有:
- SY:全系统(Full System,所有共享域)
- ISH:内共享域(Inner Shareable domain,多核间)
- NSH:非共享(Non-shareable,仅当前处理器)
- OSH:外共享域(Outer Shareable domain,包括外部设备等)
例如:
assembly
DSB SY ; 系统级别的数据同步屏障
示例:设备驱动中的使用
c
// 假设我们有一个内存映射的设备控制寄存器
volatile uint32_t *DEVICE_CMD_REG = (uint32_t *)0xFE000000;
// 向设备发送命令
*DEVICE_CMD_REG = 0x1; // 启动命令
// 确保命令写入到达设备,避免被缓冲或重排
__asm volatile("DSB SY" ::: "memory");
// 现在可以安全读取设备状态
uint32_t status = *(DEVICE_CMD_REG + 1);
与普通程序的关系
在用户空间的普通应用程序中,通常不需要直接使用 DSB,因为操作系统和硬件已经处理了大部分内存一致性。但在以下情况可能会遇到:
- 操作系统内核开发(特别是驱动、内存管理、多核同步)
- 嵌入式固件或裸机编程
- 高性能并发编程(如无锁数据结构,但在 ARM 上通常用 DMB 即可)
总结
- DSB 是一种强内存屏障,确保内存访问在系统中完成并可见。
- 它会阻塞后续指令执行,直到内存访问完成。
- 主要用于对顺序和完成时间要求严格的场景,如设备 I/O、系统配置更新等。
- 在 ARMv7 和 ARMv8 中都是重要指令,但具体作用域和选项可能随架构版本有所不同。
在编写底层系统代码时,正确使用 DSB/DMB/ISB 对保证多核、设备间的正确同步至关重要。