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 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);
In dump I could see that buf1
still contains only zeroes. When caches are turned off, result is correct so DMA itself works correctly.
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) :)
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;
, total buffer size is 4096 * sizeof(uint32_t) == 16KB