commit 784665ebcc39f650a6075283a5eeba21dbcbe160 from: Aleksey Ryndin date: Fri Oct 06 14:29:27 2023 UTC Proofread capsule/squat/reports/aarch64_exception_model.gmi commit - 10f2e38641063f4f073216bac45bbb42ac0bf9d1 commit + 784665ebcc39f650a6075283a5eeba21dbcbe160 blob - c7cde107f291ee9adb3d1e4deafb27ae1c4151ed blob + 8c947c1d7171dd4ffaa4c9393cdca351d75251df --- capsule/squat/reports/aarch64_exception_model.gmi +++ capsule/squat/reports/aarch64_exception_model.gmi @@ -2,11 +2,9 @@ Под конспектом я подразумевают укороченную версию перевода оригинального документа. Я постарался исключить повторяющиеся блоки текста без потери суммарной информации. Так же пропущен перевод некоторых примеров. Информация немного реструктурирована. -Информация применима к семействам процессорных архитектур Armv8-A и Armv9-A. - => learn_the_architecture_-_aarch64_exception_model_102412_0103_01_en.pdf Оригинальный pdf-документ (102412_0103_01_en) -Исключение это некоторое системное событие, требующее реакции со стороны привилегированного кода. Близким аналогом в других процессорных архитектурах является термин "прерывание" (interrupt). При возникновении исключения, вместо перехода к следующей инструкции, процессор приостанавливает выполнение текущего кода и переходит к исполнению фрагмента кода, отвечающего за обработку исключения. Когда исключение будет обработано, выполнение кода может быть возобновлено. +Исключение это некоторое системное событие, требующее реакции со стороны привилегированного кода. Близким аналогом в других процессорных архитектурах является термин "прерывание" (interrupt). При возникновении исключения, вместо перехода к следующей инструкции, процессор приостанавливает выполнение текущего кода и переходит к исполнению фрагмента кода, отвечающего за обработку исключения. Когда исключение будет обработано, выполнение приостановленного кода может быть возобновлено. ## Модель уровней исключений @@ -50,7 +48,7 @@ * AArch32: 32-х разрядное состояние исполнения, обеспечивающие обратную совместимость с предыдущими архитектурами. В этом состоянии поддерживаются наборы инструкций T32 и A32, а ширина регистров общего назначения составляет 32 бита. * AArch64: 64-х разрядное состояние исполнения. В этом состоянии поддерживается набор инструкций A64, а ширина регистров общего назначения составляет 64 бита. -Состояние исполнения может измениться только в момент сброса или при изменении уровня исключений. Изменение состояние исполнения при изменении уровня исключений происходит по следующим правилам: +Состояние исполнения может измениться только в момент сброса или при изменении уровня исключений. Изменение состояния исполнения при изменении уровня исключений происходит по следующим правилам: * При увеличении уровня исключений состояние исполнения остаётся прежним или становится AArch64. * При уменьшении уровня исключений состояние исполнения остаётся прежним или становится AArch32. @@ -70,7 +68,7 @@ Таким образом реализуется изоляция части данных, которая помещается в безопасное адресное пространство, к которому нет доступа из небезопасного состояния. В режиме безопасного состояния, например, могут работать платёжная система или DRM, храня изолировано платёжную информацию или криптографические ключи. -Безопасный режим возможен только на процессорах с TrustZone. В этом случае режим состояния безопасности выбирается битом SCR_EL3.NS (бит NS из регистра SCR_EL3). +Безопасный режим возможен только на процессорах с TrustZone. В этом случае режим состояния безопасности выбирается битом SCR_EL3.NS. Оба состояния безопасности (Secure state и Non-secure state) могут в общем случае присутствовать на первых трех уровнях исключений (EL0, EL1, EL2). В Armv8-A EL3 всегда работает в безопасном режиме. Armv9-A поддерживает расширение Realm Management (Realm Management Extension, RME). RME вводит еще одно состояние исполнения (Realm) и дополнительно изолирует EL3 от всех других, помещая его в новое корневое состояние (root). @@ -83,8 +81,8 @@ Исключение называется синхронным, если оно вызвано непосредственно исполняемой в момент возникновения инструкцией. Содержимое регистров при вызове синхронного исключения строго соответствует всем инструкциям, которые были выполнены ранее, до инструкции вызвавшей исключение. Более детальные примеры синхронных исключений: -* Некорректная инструкция и исключения-ловушки. Попытка выполнить инструкцию UNDEFINED, отключенную инструкцию или инструкцию, недопустимую для на текущем уровне исключений, приведёт к генерации синхронного исключения. А также архитектура позволяет устанавливать ловушки для менее привилегированного кода при попытке выполнить определенные действия. Например ядро на EL1 может установить ловушку на выполнение для EL0 на использование инструкций с плавающей запятой. По умолчанию блок операций с плавающей запятой может быть совсем отключен и при переключении контекста специфические регистры не нужно сохранять. Но после срабатывания исключения-ловушки ядро может включить блок операций с плавающей запятой, сохранить признак необходимости сохранять содержимое соответствующих регистров и повторить операцию, вызвавшую исключение. -* Обращение к памяти. При включенном MMU (блок управления памятью, Memory Management Unit) все инструкции load и store контролируются на предмет их корректности. Поэтому, например, при попытке получения доступа к привилегированному адресу из непривилегированного кода или попытке записи по адресу, доступному только для чтения, произойдёт синхронное исключение. Обработчик исключения получит управление до того, как будет продолжен доступ к памяти. Однако следует помнить, что фатальные ошибки при обращения к памяти могут вызвать и асинхронное исключение, которые будут рассмотрены далее (см. SError). +* Некорректная инструкция и исключения-ловушки. Попытка выполнить инструкцию UNDEFINED, отключенную инструкцию или инструкцию, недопустимую для на текущем уровне исключений, приведёт к генерации синхронного исключения. А также архитектура позволяет устанавливать ловушки для менее привилегированного кода при попытке выполнить определенные действия. Например ядро на EL1 может установить ловушку выполнения инструкций с плавающей запятой для EL0. По умолчанию блок операций с плавающей запятой может быть совсем отключен и при переключении контекста специфические регистры не нужно сохранять. Но после срабатывания исключения-ловушки ядро может включить блок операций с плавающей запятой, взвести признак необходимости сохранять содержимое соответствующих регистров и повторить операцию, вызвавшую исключение. +* Обращение к памяти. При включенном MMU (блок управления памятью, Memory Management Unit) все инструкции load и store контролируются на предмет их корректности. Поэтому, например, при попытке получения доступа к привилегированному адресу из непривилегированного кода или попытке записи по адресу, доступному только для чтения, произойдёт синхронное исключение. Обработчик исключения получит управление до того, как будет продолжен доступ к памяти. Однако следует помнить, что фатальные ошибки при обращении к памяти могут вызвать и асинхронное исключение, которые будут рассмотрены далее (см. SError). * Отладочные исключения: инструкция отладочного останова, отладочный останов, пошаговая трассировка и другое. * Инструкции системных вызовов. Существуют инструкции, которые намерено генерируют исключение. Это инструкции используемые для реализации интерфейса вызова более привилегированного кода. Их часто называют инструкциями системных вызовов (system call). Такие инструкции позволяют выполнить переход между уровнями исключений: SVC (Supervisor Call) для перехода с EL0 в EL1, HVC (Hypervisor Call) для перехода с EL1 в EL2 и SMC (Secure Monitor Call) для перехода с EL1 или EL2 в EL3. @@ -96,19 +94,19 @@ Более детальные примеры асинхронных исключений: * Системная ошибка (System Error) SError. Это ошибка, генерируемая от подсистемы памяти в момент возникновения неожиданного события. Текущая инструкция, исполняемая процессором, в общем случае не связана с возникшей ошибкой. Примеры таких ошибок: доступ к памяти, прошедший все проверки MMU, но встретивший ошибку на шине памяти, проверка чётности или кода коррекции ошибок памяти (Error Correction Code, ECC). Генерация SError зависит от конкретной реализации. -* Физические прерывания (Physical interrupts). Одним из способ сообщить о смене состояния периферийного устройства может быть прерывание. Сложные системы могут иметь множество источников прерываний с различными уровнями приоритета, включая возможность вложенной обработки прерываний, при которой прерывание с более высоким приоритетом может прервать прерывание с более низким приоритетом. Скорость реакции ядра на такие события может быть критически важной и называется задержкой прерывания (interrupt latency). В архитектуре arm есть два типа асинхронных исключений для обработки сигналов от периферии: IRQ и FIQ. Они имеют независимую маршрутизацию и часто используются для реализации защищённых (Secure) и незащищённых (Non-secure) прерываний. Во всех реализация arm для управления IRQ и FIQ используется универсальный контроллер прерываний (Generic Interrupt Controller, GIC). Этот контроллер приоритезирует и маршрутизирует прерывания, отправляя их процессорному ядру. +* Физические прерывания (Physical interrupts). Одним из способ сообщить о смене состояния периферийного устройства может быть прерывание. Сложные системы могут иметь множество источников прерываний с различными уровнями приоритета, включая возможность вложенной обработки прерываний. Скорость реакции ядра на такие события может быть критически важной и называется задержкой прерывания (interrupt latency). В архитектуре arm есть два типа асинхронных исключений для обработки сигналов от периферии: IRQ и FIQ. Они имеют независимую маршрутизацию и часто используются для реализации защищённых (Secure) и незащищённых (Non-secure) прерываний. Во всех реализация arm для управления IRQ и FIQ используется универсальный контроллер прерываний (Generic Interrupt Controller, GIC). Этот контроллер приоритезирует и маршрутизирует прерывания, отправляя их процессорному ядру. * Виртуальные прерывания (Virtual interrupts). Система, использующая виртуализацию, имеет более сложные требования к обработке прерываний. Некоторые прерывания может получать гипервизор, а другие могут быть обработаны непосредственно в виртуальной машине. Прерывания, которые видит виртуальная машина, являются виртуальными прерываниями: vSError (Virtual System Error), vIRQ (Virtual IRQ) и vFIQ (Virtual FIQ). Виртуальные прерывания могут быть сгенерированы извне устройством, подключенным к контроллеру прерываний, или могут быть сгенерированы программно. Виртуальные прерывания могут быть доставлены только на EL1. 🛈 В более ранних версиях arm прерывания FIQ имели более высокий приоритет относительно IRQ. В AArch64 FIQ и IRQ имеют одинаковый приоритет. ## Обработка исключений -При обработка исключений в AArch64 используется специальная терминология: +При обработке исключений в AArch64 используется специальная терминология: * Принятием исключения (taking an exception) называют момент, когда процессор реагирует на исключение. * Уровень исключения и состояние, которые исполнялись в момент принятия исключения, называются уровнем и состоянием с которого принимается исключение (taken from). * Уровень исключения и состояние, которые будут обрабатывать исключение, называются уровнем и состоянием в которые принимается исключение (taken to). -Например исключение может быть принято с AArch32 EL0 в AArch64 EL1. Обработка исключения будет происходить в AArch64 на уровне исключений EL1. После обработки исключения система должна вернуться к состоянию с которого было принято исключение. В arm для этого есть отдельные инструкции. В нашем примере возврат из из исключения перейдет обратно в AArch32 на EL0. При переходе из AArch32 в AArch64 регистры, недоступные в состоянии AArch32, сохраняют свои значения из предыдущего исполнения AArch64. Для регистров, доступных в обоих состояниях исполнения, верхняя половина 64-разрядных регистров содержит либо 0, либо старое значение. +Например исключение может быть принято с AArch32 EL0 в AArch64 EL1. Обработка исключения будет происходить в AArch64 на уровне исключений EL1. После обработки исключения система может вернуться к состоянию с которого было принято исключение. В нашем примере возврат из исключения перейдет обратно в AArch32 на EL0. При переходе из AArch32 в AArch64 регистры, недоступные в состоянии AArch32, сохраняют свои значения из предыдущего исполнения AArch64. Для регистров, доступных в обоих состояниях исполнения, верхняя половина 64-разрядных регистров содержит либо 0, либо старое значение. Соответствие между регистрами AArch32 и AArch64: * R0-R12 из AArch32 соответствуют в AArch64 регистрам X0-X12 @@ -117,7 +115,7 @@ ### Сохранение текущего состояния процессора -В AArch64 существует концепция состояния процессора, известная как PSTATE. Это состояние при принятии исключения записывается в регистр сохранённого состояния программы (Saved Program Status Register, SPSR). PSTATE содержит такие сведения, как текущий уровень исключения и флаги арифметико-логического блока (ALU). В AArch64 так же содержится: +В AArch64 существует концепция состояния процессора, известная как PSTATE. Это состояние при принятии исключения записывается в регистр сохранённого состояния программы (Saved Program Status Register): SPSR. PSTATE содержит такие сведения, как текущий уровень исключения и флаги арифметико-логического блока (ALU). В AArch64 так же содержится: * Флаги состояния * Элементы управления состоянием выполнения * Биты маски исключений (DAIF: Debug, SError asynchronous, IRQ, FIQ. Исключение не происходит, если соответствующий бит установлен) @@ -125,12 +123,10 @@ * Биты управления таймингом * Биты управления спекулятивным исполнением -Для каждого уровня исключения существует свой SPSR - SPSR_ELx. При принятии исключения используется SPSR_ELx, в которое принимается исключение (taken to). +Для каждого уровня исключения существует свой SPSR - SPSR_ELx. При принятии исключения используется SPSR_ELx, в которое принимается исключение. -🛈 В Armv7 и более ранних версиях PSTATE назывался CPSR и был реализован в виде регистра. +Для синхронных исключений и SError помимо прочего заполняется и регистр синдрома исключения (Exception Syndrome Register): ESR. В нём кодируется причина исключения. -Для синхронных исключений и SError помимо прочего заполняется и регистр синдрома исключения (Exception Syndrome Register, ESR). В нём кодируется причина исключения. - ### Маршрутизация и контроллер прерываний Каждое исключение имеет свой принимающий уровень исключений (EL), который определяется одним из условий: @@ -138,14 +134,14 @@ * Исключение маршрутизируется в соответствии с конфигурацией системных регистров. Маршрутизация задается независимо для IRQ, FIQ и SError. Настройка маршрутизации осуществляется двумя регистрами: -* Регистр конфигурации гипервизора (Hypervisor Configuration Register): HCR_EL2.Определяет какие исключения будет принимать EL2. +* Регистр конфигурации гипервизора (Hypervisor Configuration Register): HCR_EL2. Определяет какие исключения будет принимать EL2. * Регистр конфигурации монитора безопасности (Secure Configuration Register): SCR_EL3. Определяет какие исключения будет принимать EL3. Имеет более высокий приоритет относительно HCR_EL2. Исключения, маршрутизация которых не задана ни в SCR_EL3, ни в HCR_EL2 будут приниматься в EL1. При сбросе значение регистров HCR_EL2 и SCR_EL3 не определено и должно быть задано явным образом. -Для более детальной маршрутизации, управления и приоритизации используется контроллер прерываний arm (Generic Interrupt Controller, GIC). Он позволяет существенно снизить накладные расходы при виртуализации. Технические детали можно найти в техническом руководстве. +Для более детальной маршрутизации, управления и приоритизации используется контроллер прерываний arm (Generic Interrupt Controller, GIC). Он позволяет существенно снизить накладные расходы при виртуализации. Технические детали можно найти в техническом руководстве GIC. 🛈 Нельзя перенаправлять исключение на нереализованный уровень исключений. Такое поведение является неопределенным (UNDEFINED). Так же нельзя возвращаться из исключения на отключенный или нереализованный уровень исключений. Попытка выполнения инструкции возврата приведет к возникновению ошибки. @@ -163,9 +159,9 @@ При принятии исключения процессор исполняет код обработчика исключения. Место в памяти, где хранится обработчик, называется вектором исключения. -🛈 В отличии от других архитектур, в amr в векторах исключений хранятся не адреса обработчиков, а непосредственно код самого обработчика. +🛈 В отличии от других архитектур, в arm вектор исключения хранит не адрес обработчика, а непосредственно код самого обработчика. -Векторы исключений вместе образуют таблицу векторов исключений. Каждый уровень исключений, который может быть принимающим исключение, имеет свою собственную таблицу векторов, базовый адрес которой определяется собственным регистром базового адреса вектора (Vector Base Address Register) - VBAR_EL, где - это 1, 2 или 3. Значения регистров VBAR после сброса не определены, поэтому их необходимо задать явно до включения прерываний. +Векторы исключений вместе образуют таблицу векторов исключений. Каждый уровень исключений, который может принимать исключение, имеет свою собственную таблицу векторов, базовый адрес которой определяется собственным регистром базового адреса векторов (Vector Base Address Register) - VBAR_EL, где - это 1, 2 или 3. Значения регистров VBAR после сброса не определены, поэтому их необходимо задать явно до включения прерываний. Векторные таблицы используют единый формат. Таблица делится на четыре категории: * VBAR_ELx+0x000 - Исключения с текущего EL при использовании SP_EL0 @@ -177,13 +173,13 @@ * +0x000 - синхронное (Synchronous) исключение * +0x080 - IRQ/vIRQ * +0x100 - FIQ/vFIQ -* +0x180 - SError/VSError +* +0x180 - SError/vSError -Непосредственно в векторе исключения умещаются 32 процессорных инструкции, которые так же называют обработчиком первого уровня. Обычно код вектора исключения сохраняет в стеке содержимое регистров, которые могут быть изменены и вызывает функцию более сложного обработчика, специфичного для текущего исключения. После возврата содержимое регистров восстанавливается и исполняется инструкция возврата из исключения (ERET). +Непосредственно в векторе исключения умещаются 32 процессорных инструкции, которые так же называют обработчиком первого уровня (first-level handler). Обычно код вектора исключения сохраняет в стеке содержимое регистров, которые могут быть изменены, и вызывает функцию более сложного обработчика, специфичного для текущего исключения. После возврата содержимое регистров восстанавливается и исполняется инструкция возврата из исключения (ERET). ### Указатель стека при принятии исключения -В AArch64 при принятии исключения можно выбрать один из двух регистров указателя стека: SP_EL0 или SP_EL, где - текущий уровень Exception. Если исполнение происходит на уровне EL0, то безусловно используется SP_EL0. Если текущий уровень исполнения выше чем 0, то указатель сетка определяется битом SP из PSTATE: +В AArch64 при принятии исключения можно выбрать один из двух регистров указателя стека: SP_EL0 или SP_EL, где - текущий уровень исключения. Если исполнение происходит на уровне EL0, то безусловно используется SP_EL0. Если текущий уровень исполнения выше чем 0, то указатель сетка определяется битом SP из PSTATE: * Если PSTATE.SP равен 0, то используется SP_EL0. * Если PSTATE.SP равен 1, то используется SP_ELx текущего уровня исключений. @@ -193,11 +189,9 @@ Возврат из исключения осуществляется инструкцией ERET. Инструкция ERET восстанавливает предыдущее состояние процессора из соответствующего регистра SPSR_EL, где - уровень исключения, на котором выполняется обработчик исключения. А после инструкция передает управление на прерванную инструкцию, адрес которой сохранён в ELR. Оба действия (восстановление предыдущего состояния из SPSR_ELx и передача управления по адресу из ELR_ELx) выполняются атомарно. -🛈 Обратите внимание, что состояние исполнения, указанное в SPSR_ELx должно быть согласовано с SCR_EL3.RW или HCR_EL2.RW - Адрес возврата, сохранённый в ELR_ELx зависит от типа исключения: -* Для инструкций SVC, HMC и SMC регистр ELR будет указывать на следующую инструкцию. +* Для инструкций SVC, HVC и SMC регистр ELR будет указывать на следующую инструкцию. * Для остальных синхронных исключений регистр ELR будет указывать на инструкцию, породившую исключение. * Для асинхронных исключений регистр ELR будет указывать на следующую инструкцию после последней полностью выполненной инструкции. -Обработчик исключения может менять ELR_ELx по своему усмотрению. +Обработчик исключения может менять содержимое регистра ELR_ELx по своему усмотрению.