ФЭНДОМ


Общие сведения Править

В версиях до ARMv6 при описании особенностей памяти используются термины «кэшируемая со сквозной записью» (Write-Through Cacheable), «кэшируемая с обратной записью» (Write-Back Cacheable), «некэшируемая, буферируемая» (Non-Cacheable Bufferable, что подразумевает возможность буферизации обращений на запись, но запрещает кэширование считываемой информации), «некэшируемая, небуферируемая» (Non-Cacheable Non-Bufferable). Однако точного определения этих терминов спецификация не даёт, как не описывает она и порядок реального выполнения доступов процессора к памяти. Всё это протенциально порождает проблемы совместимости.

В версии ARMv6 от использования перечисленных терминов отказались. Спецификация определяет три типа памяти — обычная (Normal), память устройств (Device) и строго упорядоченная память (Strongly Ordered); кроме того, вводится понятие разделяемой (Shared) памяти, доступ к которой возможен со стороны нескольких активных устройств (в первую очередь процессоров). Хотя эти типы определены с оглядкой на совместимость с более ранними версиями архитектуры, полной совместимости во всех возможных случаях они не дают. В частности, гарантию реального завершения обращения к устройству ввода-вывода даёт лишь программный опрос определённой ячейки памяти.

Особенности различных диапазонов адресов памяти в любой версии архитектуры описываются с помощью атрибутов.

Виды обращений к памяти Править

Обращения к памяти бывают двух видов: считывание и запись. Кроме того, в отдельную группу можно вынести операции, предназначенные для синхронизации выполнения кода на разных процессорах или на одном процессоре в многозадачной среде (так называемые примитивы синхронизации).

Обращения для чтения осуществляются при выполнении следующих команд:

Обращения для записи осуществляются при выполнении следующих команд:

Кроме того, обращения для чтения и записи могут осуществляться при выполнении аппаратно реализованных команд набора Jazelle.

К примитивам синхронизации относятся четыре команды набора ARM: SWP, SWPB, LDREX, STREX. Две последних появились в версии ARMv6, одновременно с этим первая пара команд была объявлена устаревшей.

Явными обращениями называются доступы, прямо связанные с выполнением команды. Например, команды загрузки содержимого регистра из памяти порождают доступ к памяти для чтения. Помимо явных, существуют и неявные доступы; например, та же команда загрузки может вызвать неявный доступ к таблице страниц, необходимый для преобразования виртуального адреса ячейки памяти в физический.

Наблюдаемость и завершённость доступовПравить

В спецификации архитектуры ARM используются понятия наблюдаемости (observability) и завершённости (completion) доступов к памяти. Следует помнить, что архитектурой ARM не предусматривается отдельное адресное пространство ввода-вывода, поэтому под памятью понимается как собственно память (ОЗУ и ПЗУ), так и регистры внешних устройств.

Правила наблюдаемости доступов таковы:

  • запись в ячейку является наблюдаемой некоторым устройством, когда это устройство при выполнении считывания этой ячейки получит вновь записанное значение, а не хранившееся там до выполнения данной операции записи;
  • запись в ячейку является глобально наблюдаемой, когда чтение этой ячейки любым устройством вернёт вновь записанное значение;
  • считывание ячейки является наблюдаемым некоторым устройством, когда последующая запись в эту же ячейку тем же самым устройством уже не окажет влияния на считанное значение;
  • считывание ячейки является глобально наблюдаемым, когда последующая запись в эту ячейку со стороны любого устройства уже не изменит считанное значение.

Для строго упорядоченной памяти имеется дополнительное правило:

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

Правила завершённости таковы:

  • чтение или запись являются завершёнными, когда они глобально наблюдаемы, а связанные с ними обращения к таблицам переадресации завершены;
  • обращение к таблице переадресации является завершённым, когда все обращения к памяти, связанные с этой таблицей переадресации, стали глобально наблюдаемыми, а копия используемой информации из этой таблицы, находящаяся в TLB, была обновлена;
  • операции обслуживания кэшей, предсказателя ветвлений и TLB являются завершёнными, когда эффекты этих операций становятся глобально наблюдаемыми, а все связанные с этими операциями доступы к таблицам переадресации завершаются.

Все внешние устройства, доступ к которым порождает побочные эффекты, должны иметь определённый регистр (например, регистр состояния), считывание которого даёт гарантию того, что все эффекты, связанные с предыдущими доступами к этому устройству, вступили в силу. Регистры таких устройств должны находиться в областях памяти, имеющих тип «память устройства» или «строго упорядоченная память».

Ограничения на доступы к памяти Править

На доступы к памяти накладывается ряд ограничений:

  • все байты, доступ к которым осуществляется одной транзакцией, должны относиться к одному типу памяти, в противном случае результат будет непредсказуемым. По этой причине невыровненные доступы могут привести к непредсказуемым последствиям, хотя сами по себе они в версии ARMv6 являются допустимыми;
  • несколько обращений к памяти, вызванных одной и той же инструкцией (например, LDM), должны адресоваться к одному и тому же типу памяти, иначе последствия будут непредсказуемыми;
  • инструкции, вызывающие невыровненный доступ к строго упорядоченной памяти или к памяти устройств, закончатся непредсказуемыми последствиями;
  • инструкции, порождающие несколько доступов к памяти устройств или к строго упорядоченной памяти, не должны пересекать границу в 4 Кбайта, чтобы гарантировать выполнение правил доступа к этим типам памяти;
  • инструкции, вызывающие несколько доступов к памяти и явным образом обращающиеся к счётчику команд как к источнику или приёмнику, должны адресоваться только к обычной памяти, в противном случае последствия будут непредсказуемыми;
  • выборка кодов команд допустима только из обычной памяти, иначе последствия будут непредсказуемыми;
  • одна и та же физическая область памяти должна иметь одинаковые атрибуты для любого из виртуальных адресов, используемых для доступа к ней, иначе результаты будут непредсказуемыми;
  • множественные доступы к памяти со стороны одной инструкции в режиме малой задержки прерываний в некоторых реализациях могут приводить к непредсказуемым результатам, поэтому использовать их нужно с осторожностью и никогда не применять к строго упорядоченной памяти и к памяти устройств.

Упорядоченность доступов к памяти Править

Два явных доступа к памяти, из которых один концептуально предшествует другому, будут выполняться в концептуальном (см. ниже) или в произвольном порядке в зависимости от того, к каким видам памяти эти доступы относятся. Всегда выполняются в концептуальном порядке следующие доступы:

  • если хотя бы один из них адресован строго упорядоченной памяти;
  • если оба доступа выполняют чтение из неразделяемой памяти устройств;
  • если оба доступа выполняют чтение из разделяемой памяти устройств;
  • если оба доступа выполняют запись в неразделяемую память устройств;
  • если оба доступа выполняют запись в разделяемую память устройств.

Заметим, что два запроса, обращённые к памяти устройств, могут выполняться в произвольном порядке, если это разные виды запросов (один — чтение, а другой — запись) или если область память, к которой обращается один из запросов, является разделяемой, а другая область — неразделяемой.

Концептуальный порядок выполнения доступов определяется следующими правилами:

  • если два доступа вызваны двумя различными инструкциями, то концептуально более ранним будет доступ той инструкции, которая была выполнена раньше;
  • если два доступа вызваны одной и той же инструкцией, то:
    • в командах SWP и SWPB чтение концептуально предшествует записи;
    • в командах LDC, LDRD, LDM, STC, STRD и STM, за исключением LDM и STM, в числе регистров которых указан счётчик команд, доступ к ячейке памяти с меньшим адресом концептуально выполняется раньше или одновременно, но не позже доступа к ячейке с большим адресом;
    • в командах LDM и STM, в списке регистров которых указан счётчик команд, концептуальный порядок доступов к памяти не определён;
    • в командах LDRD и STRD порядок доступов к памяти является непредсказуемым, если список регистров включает счётчик команд.

Барьеры памяти Править

Барьер памяти — это общий термин, означающий инструкцию или последовательность инструкций, выполнение которых заставляет процессор не начинать выполнение следующих команд до тех пор, пока доступы к памяти, порождённые предшествующими барьеру командами, не будут реально выполнены.

В версии ARMv6 предусмотрено три вида барьеров:

  • барьер памяти данных (DMB, Data Memory Barrier);
  • барьер синхронизации данных (DSB, Data Synchronization Barrier), называемый также барьером записи данных;
  • сброс предвыборки (PrefetchFlush).

Все три вида барьеров управляются с помощью регистра 7 сопроцессора управления системой. Они могут использоваться как в привилегированных, так и в непривилегированном режимах.

В версиях, предшествовавших ARMv6, барьеры могли поддерживаться или нет по усмотрению производителя конкретной модели процессора.

Барьер памяти данныхПравить

Барьер памяти данных (DMB) проявляет себя следующим образом:

  • результаты всех явных доступов к памяти, выполняемых инструкциями до барьера, станут заметны всем наблюдателям до того, как станут заметны результаты доступов к памяти со стороны инструкций, выполняемых после барьера;
  • порядок выполнения процессором других инструкций не изменяется.

Таким образом, DMB даёт уверенность относительно порядка выполнения явных доступов к памяти до и после барьера, но не даёт гарантий их завершения.

Барьер синхронизации данных Править

Барьер синхронизации данных (DSB) исторически назывался барьером записи данных (DWB), однако в версии ARMv6 был переименован, чтобы точнее отражать его суть. Он представляет собой более жёсткую разновидность DMB:

  • все явные доступы к памяти до DSB будут полностью завершены;
  • все операции обслуживания кэшей, предсказателя ветвлений и TLB, связанные с инструкциями, предшествующими барьеру, будут полностью завершены;
  • выполнение инструкций после барьера начнётся только после того, как завершатся указанные выше действия.

Сброс предвыборки Править

Операция сброса предвыборки (PrefetchFlush) фактически останавливает и очищает конвейер процессора, благодаря чему следующие за ней инструкции будут заново выбраны и декодированы из памяти или кэша. Эта операция даёт гарантию того, что смена контекста и любые изменения в регистрах сопроцессора управления системой, а также модификация кода станут видимы для всех последующих инструкций.

Когерентность памяти Править

В системах, имеющих кэш-память, обычной является ситуация, когда содержимое ячейки с одним и тем же адресом существует в нескольких экземплярах: один экземпляр хранится в самой памяти, а ещё один или несколько могут находиться в кэш-памяти разных уровней. В определённых ситуациях это может привести к рассогласованию данных, когда в разных местах хранятся разные значения для одной и той же ячейки.

Архитектура ARM возлагает поддержание когерентности памяти, т.е. соответствия между значениями, хранящимися на различных уровнях подсистемы памяти, частично на аппаратуру, а частично на программное обеспечение. Поведение программы, нарушающей правила соблюдения когерентности, будет непредсказуемым.

До версии ARMv6 действия, необходимые для поддержания когерентности, зависели от особенностей реализации процессора. В ARMv6 методы поддержания когерентности на первом уровне иерархии подсистемы памяти (тесно связанная память и кэш-память первого уровня) стандартизированы и обеспечиваются сопроцессором управления системой (CP15).

Для поддержания когерентности программное обеспечение использует механизмы обслуживания кэша и обслуживания TLB. Связь этих операций с порядком доступа к памяти будет описана ниже.

Замечание. При описании операций, связанных с поддержанием когерентности памяти, под возвратом из исключения понимается:

  • использование инструкции обработки данных в варианте с установкой флагов и регистром PC в качестве приёмника;

Обслуживание кэша и порядок доступа к памяти Править

  • Все операции обслуживания кэша и предсказателя ветвлений выполняются по отношению друг к другу в порядке выполнения программы. Когда эти операции появляются в программе перед изменением таблиц переадресации, они будут гарантированно выполнены перед тем, как станут заметны последующие изменения в этих таблицах.
  • Когда изменения в таблицы переадресации вносятся до операций обслуживания кэша и предсказателя ветвлений, эти изменения станут гарантированно видимыми лишь после выполнения действий, описанных в подразделе Операции обслуживания TLB.
  • Любые операции обслуживания кэша, выполняемые перед DMB, будут гарантированно видимы любым явным операциям чтения и записи памяти, выполняемым после DMB. DMB также гарантирует, что любые эффекты, связанные с операциями обслуживания кэша, начатыми до DMB, станут глобально видимыми раньше аналогичных операций, а также явных доступов к памяти, следующих в программе после DMB. Однако DMB не даёт гарантии видимости всех данных другим наблюдателям (т.е. механизму выборки таблиц переадресации).
  • DSB вызывает завершение всех операций обслуживания кэша, имеющихся в программе до DSB, и гарантирует, что любые обратные записи данных станут видимы для всех наблюдателей.
  • PrefetchFlush или возврат из прерывания гарантирует, что все операции обслуживания предсказателя ветвлений, выполняемые до PrefetchFlush, будут видимы всем инструкциям, выполняемым после PrefetchFlush или возврата из прерывания.
  • Возникновение исключения гарантирует, что эффект операций обслуживания предсказателя ветвлений, выполнявшихся до точки возникновения исключения, будет виден всем инструкциям обработчика исключения.
  • Операции обслуживания кэша данных (или единого кэша) по модифицированному виртуальному адресу (MVA), должны быть выполнены в порядке, определяемом программой, до любых явных операций загрузки и записи данных, выполняемых тем же процессором по адресам, покрываемым данным MVA в кэше.
  • На порядок выполнения операций обслуживания кэша данных (или единого кэша) по MVA по отношению к явным загрузкам и записям данных, не покрываемым MVA, ограничений не накладывается. В тех случаях, когда этот порядок важен, необходимо использовать DMB.
  • Порядок выполнения операций обслуживания кэша данных (или единого кэша) по Set/Way по отношению к явным загрузкам и записям данных тем же процессором не ограничивается. Когда он важен, необходимо использовать DMB.
  • Выполнение операций обслуживания кэша данных (или единого кэша) по Set/Way не обязательно будет заметным другим «наблюдателям», пока не будет выполнен DSB.
  • Выполнение операций обслуживания кэша инструкций будет гарантировано лишь после выполнения DSB.
  • Завершение операций обслуживания кэша инструкций будет гарантированно заметным для выборки инструкций только после выполнения PrefetchFlush.

Обслуживание TLB и порядок доступа к памяти Править

  • PrefetchFlush или возврат из исключения гарантируют видимость всех предшествующих завершённых операций обслуживания TLB для всех последующих инструкций.
  • Возникновение исключения гарантирует, что все завершённые операции обслуживания TLB, появившиеся в потоке команд до точки возникновения исключения, будут видимы всем последующим инструкциям.
  • Все операции обслуживания TLB выполняются по отношению друг ко другу в порядке, определяемом программой.
  • Все операции обслуживания TLB данных (или единого TLB) не оказывают влияния на любые явные обращения к памяти, выполняемые инструкциями, следующими в программе перед этими операциями обслуживания, поэтому использование барьеров в этом случае не требуется.
  • Все операции обслуживания TLB данных (или единого TLB) будут гарантированно видимы для последующих явных операций доступа к памяти лишь после выполнения DSB, за которым следует PrefetchFlush, исключение или возврат из исключения.
  • Все операции обслуживания TLB данных (или единого TLB) будут гарантированно видимы для последующих выборок инструкций лишь после выполнения DSB, за которым следует PrefetchFlush, исключение или возврат из исключения.
  • Запись в таблицу переадресации гарантированно видна для последующей выборки из этой таблицы, вызванной необходимостью выполнения переадресации для явного доступа к памяти, лишь после выполнения DSB. Однако имеется гарантия, что никакая запись в таблицу переадресации не будет видна явным доступам к памяти, осуществляемым до этой записи.
  • Если таблицы переадресации находятся в памяти, кэшируемой с обратной записью, после внесения изменений в эти таблицы и до обращения к ним для выполнения переадресации должна быть выполнена очистка таблиц.
  • Записи в таблицы переадресации (с последующей очисткой кэша, если необходимо) будут гарантированно видны для обращений, необходимых для выполнения переадресации при выборке инструкций, следующих за этими записями, только после выполнения DSB и PrefetchFlush.

Примитивы синхронизации Править

Примитивы синхронизации (инструкуции SWP, SWPB, LDREX и STREX) подчиняются общим правилам выполнения доступов к памяти. Поэтому:

  • портируемый код, захватывающий спин-блокировку, должен иметь DMB между захватом спин-блокировки и выполнением использующих её доступов;
  • портируемый код, освобождающий спин-блокировку, должен содержать DMB перед записью, освобождающей её.

Порядок операций обслуживания предсказателя ветвлений Править

Любая инвалидация предсказателя ветвлений гарантированно возымеет эффект лишь после выполнения PrefetchFlush, исключения или возврата из исключения.

Инвалидация предсказателя ветвлений должна использоваться после следующих событий:

  • разрешения или запрещения устройства управления памятью;
  • записи новых данных по адресам, занимаемым инструкциями;
  • записи новой информации в таблицы страниц;
  • изменения TTBR0, TTBR1 или TTBCR;
  • изменения ProcessID или ContextID в FCSE.

Изменение регистров сопроцессора CP15 Править

  • Все изменения регистров сопроцессоров CP14 и CP15 не влияют на явные доступы к памяти, выполняемые до изменения этих регистров.
  • Все такие изменения будут гарантированно видны следующим инструкциям лишь после выполнения PrefetchFlush, исключения или возврата из исключения. Однако если инструкция MRC прямо считывает регистр сопроцессора, ранее записанный командой MCR, будет считано записанное значение, что исключает необходимость в синхронизации между этими двумя командами. Аналогично, если несколько команд MCR выполняют запись в один и тот же регистр, ему будет присвоено значение, заданное последней из этих инструкций.
  • Некоторые регистры CP15 для гарантии видимости внесённых в них изменений могут потребовать выполнения перед PrefetchFlush, исключением или возвратом из исключения дополнительных действий. Все такие случаи явно оговорены при описании соответствующих регистров.
  • Любое изменение состояния регистров CP15, связанное с обнаружением исключений, не вступит гарантированно в силу до тех пор, пока не произойдёт изменение, связанное с обработкой исключения. Например, если бит A регистра 1 CP15 был установлен, а бит V того же регистра был сброшен (что означает проверку выравнивания при доступах к памяти и использование таблицы векторов прерываний, размещённой с нулевого адреса), а после команды MCR, меняющей значения этих битов на противоположные (отсутствие контроля выравнивания и использование таблицы векторов прерываний по адресу FFFF_0000), следует инструкция, выполняющая доступ по невыровненному адресу, исключение «отказ данных» может как произойти, так и не произойти в зависимости от того, сразу ли проявляется изменение бита A в данной модели процессора. Однако, если исключение возникло (т.е. если было зафиксировано обращение по невыровненному адресу), переход на обработчик будет осуществляться по вектору с адресом 0000_0010, поскольку бит V был установлен одновременно со сбросом бита A, а сброс A ещё не вступил в силу, иначе бы исключение не возникло.

Синхронизация изменений ASID и TTBR Править

Чтобы ContextID был связан с новыми таблицами страниц, необходимо изменить вместе ContextID и регистр базы таблицы трансляции (TTBR). Этого можно достичь разными путями, например, следующей последовательностью действий:

1. Изменить идентификатор пространства приложения (ASID) на 0 (этот номер зарезервирован для ОС). 2. Выполнить PrefetchFlush. 3. Изменить TTBR. 4. Выполнить PrefetchFlush. 5. Изменить ASID на нужное значение.

Изменение регистра текущего состояния программы Править

  • Любые изменения CPSR с помощью команд CPS, SETEND и MSR (они работают с CPSR, не выполняя возврат из прерывания), не затрагивают команды, выполняющиеся до этих изменений.
  • Любые изменения CPSR с помощью указанных команд будут сразу заметны последующим инструкциям, за исключением изменений, связанных с уровнем привилегий. Чтобы изменение уровня привилегий гарантированно вступило в силу, необходимо выполнение PrefetchFlush, исключения или возврата из исключения.