通过虚拟地址刷新/无效范围;ARMv8;缓存; [英] Flush/Invalidate range by virtual address; ARMv8; Cache;

查看:33
本文介绍了通过虚拟地址刷新/无效范围;ARMv8;缓存;的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为 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.


所以没有实际的无效,只有干净和无效

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

Normal (at least for me) sequence is

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

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

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆