禁用DCache导致Cortex-A9上atomic_flag无法设置的问题求助
Cortex-A9禁用DCache后atomic_flag_test_and_set失败问题排查
问题背景
基于Zynq-7000的Cortex-A9处理器,在第二个CPU核上运行裸机代码时,调用DCacheDisable()禁用数据缓存后,atomic_int类型的变量无法通过atomic_flag_test_and_set()设置;不调用禁用缓存的函数时,代码运行完全正常。
触发代码
#define XREG_CONTROL_DCACHE_BIT (0X00000001U << 2U) #define XREG_CP15_SYS_CONTROL "p15, 0, %0, c1, c0, 0" #define mfcp(rn) ({uint32_t rval = 0U; \ __asm__ __volatile__(\ "mrc " rn "\n"\ : "=r" (rval)\ );\ rval;\ }) #define mtcp(rn, v) __asm__ __volatile__(\ "mcr " rn "\n"\ : : "r" (v)\ ); static void DCacheDisable(void) { uint32_t CtrlReg; /* clean and invalidate the Data cache */ CtrlReg = mfcp(XREG_CP15_SYS_CONTROL); CtrlReg &= ~(XREG_CONTROL_DCACHE_BIT); /* disable the Data cache */ mtcp(XREG_CP15_SYS_CONTROL, CtrlReg); } int main(void) { DCacheDisable(); atomic_int flag = 0; printf("Before\n"); atomic_flag_test_and_set(&flag); printf("After\n"); }
执行时的汇编循环
dmb ish ldrexb r1, [r3] ; bne jumps here strexb r0, r2, [r3] cmp r0, #0 bne -20 ; addr=0x1f011614: main + 0x00000060 dmb ish
执行时寄存器r0始终为1,说明strexb指令执行失败。
工具链信息
- Vitis 2022.2
- arm-xilinx-eabi-gcc.exe (GCC) 11.2.0
- 编译选项:
-O2 -std=c11 -mcpu=cortex-a9 -mfpu=vfpv3 -mfloat-abi=hard
排查技术思路
- 内存属性配置检查:Cortex-A9禁用DCache后,内存访问直接走AXI总线,需确保
atomic_int变量所在内存区域配置为**可共享(Shareable)**属性,且内存类型为Device或Normal Non-cacheable Shareable。裸机环境下需检查MMU页表,确保该区域支持独占访问——非共享的非缓存内存无法响应独占监控信号,会导致strexb返回失败。 - 独占监控器重置:禁用DCache前可能未正确清理独占监控器状态,导致
ldrexb无法标记独占区域。可在禁用缓存前添加指令重置本地独占监控器:mov r0, #0 mcr p15, 0, r0, c7, c10, 4 ; DSB mcr p15, 0, r0, c7, c10, 5 ; DMB mcr p15, 0, r0, c15, c1, 0 ; 重置本地独占监控器 - OpenAMP原子操作适配:检查OpenAMP库中
atomic_flag_test_and_set的实现是否适配裸机无Cache场景。部分实现默认依赖Cache开启,需确保指令序列包含正确的内存屏障,且编译器能正确识别原子访问的内存地址。 - 编译器优化规避:
-O2优化可能导致atomic_int变量被优化到寄存器中,可添加volatile修饰(或使用__attribute__((aligned(4)))确保变量4字节对齐——Cortex-A9原子操作要求地址对齐,不对齐会导致strexb失败)。 - CPU核初始化验证:第二个CPU核启动时需确保内存控制器(如Zynq DDR控制器)配置正确,AXI总线的独占访问功能已启用,避免因内存系统未初始化导致原子操作失败。
内容的提问来源于stack exchange,提问作者hellow
相关产品推荐
相关产品推荐

