按虚拟地址刷新/无效范围; ARMv8;高速缓存;

时间:2017-02-07 03:55:52

标签: arm cpu-cache armv8

我正在为以32位模式运行的ARMv8(Cortex-A53)实现缓存维护功能。 当我尝试使用虚拟地址(VA)刷新内存区域时出现问题。 DCacheFlushByRange看起来像这样

// 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字节对齐的。测试

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本身可以正常工作。

其他一点是当整个D-cache被set / way结果刷新/无效时是正确的。

// loops th/ way & set for L1 & L2
asm volatile("mcr   p15, 0, %0,  c7, c14,  2" : : "r"(setway) :)

很快通过set / way正确工作来刷新/无效。使用VA闪烁/无效的情况也是如此。可能有什么问题?

PS:kBufSize=4096;,总缓冲区大小为4096 * sizeof(uint32_t) == 16KB

1 个答案:

答案 0 :(得分:1)

功能本身没有问题,而不是Cortex-A53缓存实现功能。

来自Cortex-A53 TRM

  

AArch32中的DCIMVAC操作和AArch64中的DC IVAC指令执行目标地址的无效。如果群集中的数据是脏的,则在无效之前执行清理。


因此,没有实际的无效,清除和无效

正常(至少对我而言)序列是

flush(src);
dma(); // copy src -> dst
invalidate(dst);

但是由于invalidate()确实刷新了,所以在DMA传输之后,来自缓存(dst区域)的旧数据被写在内存中的数据之上。


解决方案/解决方法是

flush(src);
invalidate(dst);
dma(); // copy src -> dst