为什么 DSB 不刷新缓存?

Why does DSB not flush the cache?

我正在使用 LWIP 和 HAL 驱动程序在 STM32H725VG 上调试 HTTP 服务器,这些驱动程序最初都是由 STM32CubeMX 生成的。问题是在某些情况下,通过 HAL_ETH_Transmit 发送的数据有一些八位字节被 0x00 替换,并且这个损坏的内容成功到达客户端。

我检查过作为参数传递给 HAL_ETH_Transmit 的缓冲区中的数据在调用此函数之前和之后是否完好无损。因此,显然,损坏发生在从 RAM 到 MAC 的传输过程中,因为校验和是根据损坏的数据计算的。所以我认为问题可能是由于缓存和 DMA 之间的交互造成的。我试过禁用 D-cache,然后就没有发生损坏。

然后我想我应该只使用 __DSB() 指令将缓存数据写入 RAM。启用 D-cache 后,我在调用 HAL_ETH_Transmit 之前添加了 __DSB() (它在 STM32CubeMX 生成的 low_level_output 函数中),并且......没有任何反应:数据仍然存在已损坏。

然后,经过一些实验,我发现 SCB_CleanDCache()__DSB() 之后(或代替)调用可以解决问题。

这让我很奇怪。 DSB指令的描述为as follows:

Data Synchronization Barrier acts as a special kind of memory barrier. No instruction in program order after this instruction executes until this instruction completes. This instruction completes when:

  • All explicit memory accesses before this instruction complete.
  • All Cache, Branch predictor and TLB maintenance operations before this instruction complete.

并且 description of SCB_DisableDCache 有以下关于 SCB_CleanDCache 的注释:

When disabling the data cache, you must clean (SCB_CleanDCache) the entire cache to ensure that any dirty data is flushed to external memory.

如果缓存应该在“所有显式内存访问”完成时完成,为什么 DSB 不刷新缓存,这似乎包括缓存的刷新?

dsb ish 作为线程间内存顺序的内存屏障;它只是命令当前 CPU 访问一致缓存。您不会期望 dsb ish 刷新任何缓存,因为在同一内部可共享缓存一致性域中不需要可见性。正如你引用的手册中所说,它完成了内存操作。

写回缓存上的可缓存内存操作仅更新缓存;等待它们完成并不意味着刷新缓存。

我认为您的 ARM 系统对于微控制器和 DSP 具有多个一致性域?您的 __DSB 内在编译为 dsb sy 指令吗?假设不刷新缓存,他们的意思大概是它命令内存/缓存操作,包括显式刷新,这仍然是必要的。

我会把钱花在性能上。

Flushing cache是​​指将数据从缓存写入内存。内存访问速度慢。

L1 缓存大小(假设 ARM Cortex-A9)为 32KB。您不想无缘无故地将整个 32KB 从缓存移动到内存中。可能有 L2 缓存,很容易达到 512KB-1MB(可能更多)。你真的不想移动整个 L2。

事实上,您的整个 DMA 传输可能小于缓存的大小。根本没有理由这样做。