Очистить / аннулировать диапазон по виртуальному адресу; ARMv8; Кэш;

Я реализую функции обслуживания кеша для 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-кеш сбрасывается / становится недействительным по результату set / way.

// 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


person user3124812    schedule 07.02.2017    source источник
comment
Вероятно, вам следует просто очистить весь кеш L1, если диапазон / буфер большой, а затем сделать паузу, чтобы убедиться, что он завершился, прежде чем очищать кеш L2. Кроме того, имеется буфер записи (или что-то подобное), который не является частью кеша. Вы не указываете размеры, равно как и значение «buf1» полностью или частично. Наборы обычно представляют собой последовательные адреса.   -  person artless noise    schedule 07.02.2017
comment
Размер буфера составляет 16 КБ. Еще пробовал буфер 64Б, результат тот же. Не работает очистка всей области L1 и L2 с помощью VA. Целый буфер назначения во всех случаях равен нулю.   -  person user3124812    schedule 08.02.2017
comment
Извините, я не знаком с A53, однако на Cortex-A7 есть интерфейс регистров с отображением памяти для L2. Регистры CP15 не очищают кэш L2 (даже если это может показаться в руководстве). Есть ли у вас руководство по ARM помимо Cortex-A53 TRM? Обычно SCU, встроенные таймеры и т. Д. Имеют отдельные файлы регистров, по крайней мере, с более ранними чипами ARM. Linux использует разные механизмы в cache.S.   -  person artless noise    schedule 08.02.2017
comment
@artlessnoise L2 Cache Controller - это отдельный чип в A7 (как и другие периферийные устройства, даже если они все упакованы вместе). A53 имеет встроенный кэш L2.   -  person user3124812    schedule 09.02.2017


Ответы (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
invalidate(dst); // again, that's right*.


* Данные из области памяти dst могут быть загружены в кеш заранее. Если это произойдет до того, как DMA поместит данные в память, будут использоваться старые данные из кеша. Вторая недействительность - это нормально, поскольку данные не помечены как «грязные», она будет выполнена как «чистая недействительность». Никакой очистки / промывки в этом случае.

person user3124812    schedule 16.02.2017