通过虚拟地址刷新/使范围无效; ARMv8;缓存; [英] Flush/Invalidate range by virtual address; ARMv8; Cache;
问题描述
我正在为32位模式下运行的ARMv8(Cortex-A53)实现缓存维护功能.
当我尝试通过使用虚拟地址(VA)刷新内存区域时出现问题. DCacheFlushByRange
看起来像这样
I'm implementing cache maintenance functions for ARMv8 (Cortex-A53) running in 32 bit mode.
There is a problems when I try to flush memory region by using virtual addresses (VA). DCacheFlushByRange
looks like this
// some init.
// kDCacheL1 = 0; kDCacheL2 = 2;
while (alignedVirtAddr < endAddr)
{
// Flushing L1
asm volatile("mcr p15, 2, %0, c0, c0, 0" : : "r"(kDCacheL1) :); // select cache
isb();
asm volatile("mcr p15, 0, %0, c7, c14, 1" : : "r"(alignedVirtAddr) :); // clean & invalidate
dsb();
// Flushing L2
asm volatile("mcr p15, 2, %0, c0, c0, 0" : : "r"(kDCacheL2) :); // select cache
isb();
asm volatile("mcr p15, 0, %0, c7, c14, 1" : : "r"(alignedVirtAddr) :); // clean & invalidate
dsb();
alignedVirtAddr += lineSize;
}
DMA用于验证功能. DMA将一个缓冲区复制到另一个缓冲区.在DMA之前刷新源缓冲区,在DMA完成之后使目标缓冲区无效.缓冲区是64字节对齐的.测试
DMA is used to validate the functions. DMA copies one buffer into another. Source buffer is flushed before DMA, destination buffer is invalidated after DMA completion. Buffers are 64 bytes aligned. Test
for (uint32_t i = 0; i < kBufSize; i++)
buf1[i] = 0;
for (uint32_t i = 0; i < kBufSize; i++)
buf0[i] = kRefValue;
DCacheFlushByRange(buf0, sizeof(buf0));
// run DMA
while (1) // wait DMA completion;
DCacheInvalidateByRange(buf1, sizeof(buf1));
compare(buf0, buf1);
在转储中,我可以看到buf1
仍然仅包含零.关闭缓存后,结果是正确的,因此DMA本身可以正常工作.
In dump I could see that buf1
still contains only zeroes. When caches are turned off, result is correct so DMA itself works correctly.
另一点是整个D-cache被set/way结果刷新/无效的时候.
Other point is when whole D-cache is flushed/invalidated by set/way result is correct.
// loops th/ way & set for L1 & L2
asm volatile("mcr p15, 0, %0, c7, c14, 2" : : "r"(setway) :)
很快,按设置/方式冲洗/无效即可正常工作.通过使用VA闪烁/无效也不会.可能是个问题吗?
So shortly flush/invalidate by set/way work correctly. The same by flashing/invalidating using VA doesn't. What could be a problem?
PS:kBufSize=4096;
,总缓冲区大小为4096 * sizeof(uint32_t) == 16KB
PS: kBufSize=4096;
, total buffer size is 4096 * sizeof(uint32_t) == 16KB
推荐答案
该函数本身而不是Cortex-A53缓存实现功能没有问题.
There is no a problems w/ the function itself rather than Cortex-A53 cache implementation features.
来自Cortex-A53 TRM
From Cortex-A53 TRM
AArch32中的DCIMVAC操作和AArch64中的DC IVAC指令使目标地址无效.如果数据在群集中不干净,则在无效之前执行清除.
DCIMVAC operations in AArch32 and DC IVAC instructions in AArch64 perform an invalidate of the target address. If the data is dirty within the cluster then a clean is performed before the invalidate.
因此没有实际的失效,有清除并失效
So there is no actual invalidate, there's clean and invalidate
正常(至少对我来说)的顺序是
Normal (at least for me) sequence is
flush(src);
dma(); // copy src -> dst
invalidate(dst);
但由于invalidate()会刷新,因此在进行DMA传输后,来自缓存(dst区域)的旧数据将写入内存中的数据顶部.
But due to invalidate() does flush, old data from cache (dst region) is written on top of data in memory after DMA transfer.
解决方案/解决方法是
Solution/workaround is
flush(src);
invalidate(dst);
dma(); // copy src -> dst
invalidate(dst); // again, that's right*.
*来自"dst"存储区的数据可以提前获取到高速缓存中.如果在DMA将数据放入内存之前发生这种情况,将使用缓存中的旧数据.第二个失效是可以的,因为数据没有被标记为脏",它将被执行为纯失效".在这种情况下,请不要进行清洁/冲洗.
* Data from 'dst' memory region could be fetched into a cache in advance. If that happens before DMA put data in memory, an old data from cache would be used. Second invalidate is fine, since data is not marked as 'dirty', it would be performed as 'pure invalidate'. No clean/flush in this case.
这篇关于通过虚拟地址刷新/使范围无效; ARMv8;缓存;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!