You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ARM/ARM64 NORMAL_NC内存属性读写与内存屏障的DDR测试正确性问询

DDR读写正确性测试的屏障与内存属性问题

我需要测试DDR的正确性,逻辑是向DDR某地址写入值,确保写入完成后再读取该地址并校验值是否一致。示例C代码如下:

unsigned long test(volatile unsigned long *vaddr, unsigned long val)
{
    *vaddr = val;
    __asm__ volatile ("dsb sy":::"memory");
    return *vaddr;
}

假设vaddr采用**Write Combine(NORMAL_NC)**内存属性,物理地址对应DDR RAM,核心要求有两点:

  1. 确保val确实写入DDR,至少要让CPU向外部总线发出写请求,而非仅停留在CPU内部缓存;
  2. 确保读取的是DDR中的值,至少要让CPU向外部总线发出读请求,而非使用缓存或指令预测的数据。

我整理了一些信息,想请人指正错误:

  • (1) Write Combine是x86概念,ARM/ARM64的NORMAL_NC属性功能类似;Linux中pgprot_writecombine属性对应ARM64的NORMAL_NC映射属性,相关编码显示NORMAL_NC不使用L1/L2/L3缓存,这点和x86一致。
  • (2) x86的Write Combine属性会用到Write Buffer,ARM/ARM64的NORMAL_NC模式是否有类似的Write Buffer?
  • (3) x86/ARM/ARM64均不存在读缓冲区。
  • (4) x86/ARM/ARM64的Write Combine(NORMAL_NC)属性可能存在内存重排序,x86混合读写相关内存时有两种行为,但没找到ARM/ARM64的相关信息。
  • (5) DMA内存可能采用Write Combine映射,Linux代码中dma_mb()使用dmb(osh),我认为示例代码中至少osh屏障能确保写请求发至CPU外部。

我的两个猜测:

  1. ARM/ARM64的NORMAL_NC内存属性下,CPU可能进行推测执行,无屏障时可能出现读操作取到错误值或不执行读的情况;
  2. 示例代码中的dmb osh可确保写请求发至CPU外部总线后再执行读操作,且读操作会向外部总线发请求并使用返回值。

请问我的猜测是否正确?


解答

先纠正你整理信息中的错误点:

  1. 关于(2):ARM/ARM64的NORMAL_NC模式确实有类似x86 Write Buffer的结构——Store Buffer。所有ARM/ARM64核心都配备Store Buffer,用于暂存未完成的写操作,即使是NORMAL_NC这类非缓存内存,写操作也会先进入Store Buffer,再逐步发往外部总线。
  2. 关于(3):这个说法不完全准确。ARM/ARM64存在Load Buffer(读缓冲区),用于暂存预取的读数据或未完成的读请求结果,x86也有类似的Load Queue结构。不过Load Buffer的行为和Store Buffer不同,不会像写缓冲那样延迟写操作的可见性,但会影响读操作的重排序规则。
  3. 关于(4):ARM/ARM64的NORMAL_NC内存属性有明确的重排序规则:对于同一内存区域的读写操作,默认允许写后读重排序(即读操作可能在之前的写操作完成前执行),但不允许读后写、写后写、读后读的重排序(针对同一地址)。而跨地址的读写重排序是允许的,这点和x86的Write Combine行为有差异。

关于你的猜测验证:

  1. 猜测1正确:在NORMAL_NC属性下,ARM/ARM64的推测执行(尤其是预取读)可能导致读操作提前执行,甚至直接读取Store Buffer中未提交到外部总线的写数据(如果是同一地址),或者因为重排序,读操作在写请求发往DDR前就完成,导致读到旧值。另外,volatile关键字只能确保编译器不优化读写操作,但无法阻止CPU层面的重排序和推测执行。
  2. 猜测2部分正确,需补充细节:
    • dmb osh确实能确保所有在屏障之前的写操作(针对NORMAL_NC内存)都已提交到外部总线(即写请求已经离开CPU的Store Buffer,发往DDR方向),之后才会执行屏障后的读操作。
    • 但要确保读操作直接从外部总线获取数据,还需要注意:NORMAL_NC内存本身是非缓存的,所以读操作不会命中缓存,必然会向外部总线发请求。不过如果没有屏障,读操作可能和之前的写操作重排序,导致读到旧值;加上dmb osh后,就能保证读操作看到的是写入DDR后的最新值。
    • 另外,示例代码中使用的dsb sy比dmb osh更强:dsb sy会等待所有内存操作(包括读写)完成(即数据实际到达DDR或从DDR返回),而dmb osh只保证操作的顺序性(写操作先于读操作提交到外部)。对于DDR测试场景,dmb osh已经足够满足需求,dsb sy是过度严谨,但也没问题。

内容的提问来源于stack exchange,提问作者untitled

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.09 12:04:50