Как области памяти на ARM Cortex A обозначаются как устройства или строго упорядочены в Linux

На ARM Cortex-A9, который является частью Zynq SoC, которую я использую, области памяти помечены как обычные, устройства или строго упорядоченные. Это описано в техническом справочнике по Zynq. manual, но я понимаю, что это свойство ARM в целом. Очевидно, что возможность иметь строго упорядоченный доступ к памяти для устройств с отображением памяти (которые включают в себя многие в фабрике FPGA) должна несколько упростить программное обеспечение, поэтому желательно настроить.

Я использую драйвер UIO для сопоставления памяти устройства с пользовательским пространством, в котором работает основная часть драйвера. Согласно по этой ссылке драйвер UIO устанавливает отображаемую память как устройство/строго упорядоченное. К сожалению, это единственная ссылка, которую я могу найти на это, и прежде чем я начну вырывать барьеры памяти из своего кода, я хотел бы иметь немного больше уверенности в том, что происходит.

В настоящее время мне непонятно, как ядро ​​Linux обозначает области памяти определенного типа. Мне кажется, что свойства MT_* обозначают что-то в этом роде, но я не могу найти определения каждого типа. Я также не могу понять, как драйвер UIO определяет конкретную память.

Любые указания о том, как задаются свойства памяти в Linux, либо в общих чертах, либо, в идеале, со ссылкой на UIO, были бы исключительно полезны. Я рад иметь это в виде указателя на документацию.


person Henry Gomersall    schedule 29.11.2020    source источник


Ответы (1)


Есть несколько частей к этому.

В ARMv7, который включает Zynq-7000, память обозначается как заданный тип атрибутами области памяти, настроенными с помощью дескрипторов таблицы преобразования. Существуют различные способы их настройки, и механизмы описаны в разделе B3.8 архитектуры ARM. Справочное руководство ARMv7-A. Также полезно Zynq техническое справочное руководство., менее полный в отношении ARM, но более простой в обработке.

В широком смысле интерес представляют биты B (буферизуемый), бит C (кэшируемый) и 3 бита TEX (расширение типа). Они могут быть установлены напрямую или через перенаправление, когда установлен бит SCTLR.TRE (что фактически позволяет пользовательское переназначение с использованием регистров PRRR и NMRR - может быть, это еще что-то, но я не могу сразу увидеть что).

Дескрипторы таблицы перевода настраиваются в Linux в подсистеме блока управления памятью (MMU). Это, очевидно, очень специфично для архитектуры, и соответствующие биты ARM находятся в arch. /рука/мм. Интересно полистать mmu.c чтобы увидеть, как разные атрибуты памяти настраиваются для разных типов.

То, что следует ниже, является немного более спекулятивным, но я думаю, что оно является точным.

Драйвер ядра UIO устанавливает соответствующую защиту памяти на физическом устройстве, вызывая pgprot_noncached(). Теперь я думаю, что это делегировано конкретной реализации архитектуры, которая в случае ARMv7 является макросом, определенным в arch/arm/include/asm/pgtable.h и устанавливает флаг L_PTE_MT_UNCACHED.

Константа L_PTE_MT_UNCACHED, в свою очередь, устанавливается в arch/arm/include/asm/pgtable-2level.h. В этом файле есть хорошая документация, описывающая, что представляют собой различные константы. Значение для каждого типа переназначается на биты B, C и TEX либо с помощью перенаправления TRE, либо с помощью справочной таблицы, настроенной в arch/arm/mm/proc-macros.S. Регистры перенаправления TRE (PRRR и NMRR), я думаю, настроены в arch/arm/mm/proc-v7-2level.S. Если вы отследите их, вы получите те же значения, что и в справочной таблице (которая ссылается на константы, определенные в arch/arm/include/asm/pgtable-2level-hwdef.h — обратите внимание, что эти константы предназначены для небольшого дескриптора таблицы страниц. , отличные от используемых в mmu.c)

Где это оставляет нас? Драйвер UIO, конфигурирующий часть памяти как pgprot_noncached(), подразумевает, что это L_PTE_MT_UNCACHED, что, в свою очередь, подразумевает TEX = 000, B = 0 и C = 0. Просматривая эти настройки в справочном руководстве, мы видим, что это соответствует небуферизованной, строго упорядоченной, совместно используемой области памяти (обозначается строго типизированной).

Очевидно, что для изменения устройства (возможно, чтобы разрешить буферизованную запись) нам нужно изменить конфигурацию драйвера памяти, чтобы использовать, например. pgprot_writecombine(), который установит нормальный тип памяти, но с отключенным кешем. Существует также макрос pgprot_device(), который также настраивает тип памяти устройства (буферизуемая) и отключает кэш, но с некоторыми дополнительными флагами, которые я еще не понял должным образом (думаю, они предназначены для настройки программной Linux-версии записи таблицы страниц для случай, когда аппаратное обеспечение не поддерживает это, поэтому не имеет значения, когда оно поддерживает).

person Henry Gomersall    schedule 01.12.2020