Сбросить / Неправильный диапазон по виртуальному адресу; ARMv8; Cache;

Я реализую функции обслуживания кэша для ARMv8 (Cortex-A53), работающего в 32-битном режиме. Существует проблема, когда я пытаюсь очистить область памяти с помощью виртуальных адресов (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-кэш сбрасывается / аннулируется заданным / правильным способом.

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

Так что в скором времени сбросьте / сделайте недействительным настройку / способ работы правильно. То же самое с помощью мигания / аннулирования с помощью VA нет. В чем может быть проблема?

PS: kBufSize=4096;, общий размер буфера 4096 * sizeof(uint32_t) == 16KB

1 ответ

Решение

Нет проблем с самой функцией, а не с особенностями реализации кеша Cortex-A53.

От Cortex-A53 TRM

Операции DCIMVAC в командах AArch32 и DC IVAC в AArch64 выполняют недействительный целевой адрес. Если данные загрязнены в кластере, то очистка выполняется до аннулирования.


Таким образом, нет фактического аннулирования, есть чистый и недействительный

Нормальная (по крайней мере для меня) последовательность

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

Но из-за invalidate() сбрасывает, старые данные из кеша (область dst) записываются поверх данных в памяти после передачи DMA.


Решение / обходной путь

flush(src);
invalidate(dst);
dma(); // copy src -> dst
Другие вопросы по тегам