为什么 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 传输可能小于缓存的大小。根本没有理由这样做。
我正在使用 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 传输可能小于缓存的大小。根本没有理由这样做。