commit 10f2e38641063f4f073216bac45bbb42ac0bf9d1 from: Aleksey Ryndin date: Thu Oct 05 16:51:05 2023 UTC Append squat/reports/aarch64_exception_model.gmi (RC) commit - b31ea8b9c984deb656dae7ff9495a95baa776b86 commit + 10f2e38641063f4f073216bac45bbb42ac0bf9d1 blob - f253a661275208219a89f1899fbb4b1058bfff86 blob + c7cde107f291ee9adb3d1e4deafb27ae1c4151ed --- capsule/squat/reports/aarch64_exception_model.gmi +++ capsule/squat/reports/aarch64_exception_model.gmi @@ -1,12 +1,16 @@ # Конспект документа AArch64 Exception Model (arm, 102412_0103_01_en) +Под конспектом я подразумевают укороченную версию перевода оригинального документа. Я постарался исключить повторяющиеся блоки текста без потери суммарной информации. Так же пропущен перевод некоторых примеров. Информация немного реструктурирована. + +Информация применима к семействам процессорных архитектур Armv8-A и Armv9-A. + => learn_the_architecture_-_aarch64_exception_model_102412_0103_01_en.pdf Оригинальный pdf-документ (102412_0103_01_en) -Исключение это некоторое системное событие, требующее реакции со стороны привилегированного кода. Близким аналогом в других процессорных архитектурах является термин "прерывание" (interrupt). При возникновении исключения вместо перехода к следующей инструкции процессор приостанавливает выполнение текущего кода и переходит к исполнению фрагмента кода, отвечающего за обработку исключения. Когда исключение будет обработано, выполнение кода может быть возобновлено. +Исключение это некоторое системное событие, требующее реакции со стороны привилегированного кода. Близким аналогом в других процессорных архитектурах является термин "прерывание" (interrupt). При возникновении исключения, вместо перехода к следующей инструкции, процессор приостанавливает выполнение текущего кода и переходит к исполнению фрагмента кода, отвечающего за обработку исключения. Когда исключение будет обработано, выполнение кода может быть возобновлено. -## Модель уровней исключений для архитектуры AArch64 +## Модель уровней исключений -Модель уровней исключений для архитектуры AArch64 является в том числе моделью разграничения привилегий семейств Armv8-A и Armv9-A. Уровень исключения (анг: Exception level) часто сокращают до аббревиатуры EL. Уровни нумеруются, поэтому для указания конкретного уровня используется запись ELx, где x это число от 0 до 3. Чем ниже численное значение уровня исключения, тем меньшими привилегиями он обладает. То есть наименее привилегированный уровень исключения это EL0. +Модель уровней исключений для архитектуры AArch64 является (в числе прочего) моделью разграничения привилегий. Уровень исключений (Exception level) часто сокращают до аббревиатуры EL. Уровни нумеруются, поэтому для указания конкретного уровня используется запись EL, где x это число от 0 до 3 включительно. Чем ниже численное значение уровня исключений, тем меньшими привилегиями он обладает. То есть наименее привилегированный уровень исключения это EL0. Обычно распределение по уровням исключений выглядит так: * EL0 - пользовательские приложения @@ -14,18 +18,16 @@ * EL2 - гипервизор (Hypervisor) * EL3 - монитор безопасности (Secure Monitor) -Обязательными к реализации являются только первые два уровня исключений (EL0 и EL1). EL2 и EL3 являются необязательными к реализации. -Arm архитектура не имеет строго определения какие компоненты на каких уровнях должны располагаться. Но это руководство предполагает, что компоненты распределены как описано в предыдущем абзаце. +Обязательными к реализации являются только первые два уровня исключений (EL0 и EL1). Уровни EL2 и EL3 являются необязательными к реализации. Arm архитектура не имеет строго определения какие компоненты на каких уровнях должны располагаться. Но это руководство предполагает, что компоненты распределены как описано в предыдущем абзаце. Уровень исключения изменяется в случае: -* возникновение исключения -* возврат из исключения -* сброс процессора -* переход в режим отладки -* выход из режима отладки +* Возникновение исключения. +* Возврат из исключения. +* Сброс процессора. +* Переход в режим отладки. +* Выход из режима отладки. -При возникновении исключения уровень исключения может увеличиться или остаться прежним (никогда не уменьшается). При возврате из исключения уровень исключения может уменьшиться или остаться прежним (никогда не увеличивается). -🛈 Еще одно ограничение: исключение не может быть обработано на уровне 0 (EL0). +При возникновении исключения уровень исключения может увеличиться или остаться прежним (никогда не уменьшается). При возврате из исключения уровень исключения может уменьшиться или остаться прежним (никогда не увеличивается). Плюс исключение не может быть обработано на уровне 0 (EL0), то есть если исключение возникает в момент исполнения кода на EL0, то для обработки уровень исключения всегда будет повышен. ## Привилегии и доступ @@ -44,7 +46,7 @@ Arm архитектура не имеет строг ## Текущее состояние исполнения (Execution state) -Текущее состояние исполнения (Execution state) определяет стандартную разрядность регистров общего назначения и доступный набор инструкций. Семейства Armv8-A и Armv9-A поддерживают два состония исполнения: +Текущее состояние исполнения (Execution state) определяет разрядность регистров общего назначения и доступный набор инструкций. Семейства Armv8-A и Armv9-A поддерживают два состония исполнения: * AArch32: 32-х разрядное состояние исполнения, обеспечивающие обратную совместимость с предыдущими архитектурами. В этом состоянии поддерживаются наборы инструкций T32 и A32, а ширина регистров общего назначения составляет 32 бита. * AArch64: 64-х разрядное состояние исполнения. В этом состоянии поддерживается набор инструкций A64, а ширина регистров общего назначения составляет 64 бита. @@ -56,7 +58,7 @@ Arm архитектура не имеет строг Архитектура Armv8-A поддерживает AArch32 и AArch64 на всех уровнях исключений. То есть все четыре уровня, теоретически, могут быть 32-х битными, но это может быть ограничено конрекретной реализацией. Начальное состояние после сброса не задано и определяется конкретной реализацией. Для более конкретной информации стоит обратиться к техническому справочному руководству (Technical Reference Manual, TRM) процессора. -Архитектура Armv8-A AArch64 на всех уровнях исключений. А AArch32 может быть только на нулевом уровне исключений (EL0). Начальное состояние после сброса всегда AArch64. +Архитектура Armv9-A поддерживает AArch64 на всех уровнях исключений. А AArch32 может быть только на нулевом уровне исключений (EL0). Начальное состояние после сброса всегда AArch64. Состояние исполнения текущего уровня исключений определяется управляющим регистром следующего (более привилегированного) уровня исключений: регистры HCR_EL2 (ypervisor Configuration Register) и SCR_EL3 (Secure Configuration Register). @@ -64,7 +66,7 @@ Arm архитектура не имеет строг Возможно два состояния безопасности: * Безопасное состояние (Secure state), когда доступны как безопасное адресное пространство, так и небезопасное. -* Небезопасное состояние (Non-secure state или Normal world), когда доступно только небезопасное адресное пространство. +* Небезопасное состояние (Non-secure state) или обычный мир (Normal world), когда доступно только небезопасное адресное пространство. Таким образом реализуется изоляция части данных, которая помещается в безопасное адресное пространство, к которому нет доступа из небезопасного состояния. В режиме безопасного состояния, например, могут работать платёжная система или DRM, храня изолировано платёжную информацию или криптографические ключи. @@ -74,32 +76,27 @@ Arm архитектура не имеет строг ## Типы исключений -В архитектуре arm исключения делятся на два больших типа: (synchronous) синхронные и (asynchronous) асинхронные. +В архитектуре arm исключения делятся на два больших типа: синхронные (synchronous) и асинхронные (asynchronous). ### Синхронные (synchronous) исключения -Исключение называется синхронным, если оно вызвано непосредственно исполняемой в момент возникновения инструкцией. Содержимое регистров при вызове синхронное исключения строго соответствует всем инструкциям, которые были выполнены ранее, до инструкции вызвавшей исключение. +Исключение называется синхронным, если оно вызвано непосредственно исполняемой в момент возникновения инструкцией. Содержимое регистров при вызове синхронного исключения строго соответствует всем инструкциям, которые были выполнены ранее, до инструкции вызвавшей исключение. Более детальные примеры синхронных исключений: -* Некорректная инструкция и исключения-ловушки. Попытка выполнить инструкцию UNDEFINED, отключенную инструкцию или инструкцию, недопустимую для на текущем уровне исключений, приведёт к генерации синхронного исключения. Плюс архитектура позволяет устанавливать ловушки для менее привилегированного кода при попытке выполнить определенные действия. Например ядро на EL1 может установить ловушку на выполнение для EL0 на использование инструкций с плавающей запятой. По умолчанию блок операций с плавающей запятой может быть совсем отключен и при переключении контекста специфические регистры не нужно сохранять. Но после срабатывания исключения-ловушки ядро может включить блок операций с плавающей запятой, сохранить признак необходимости сохранять содержимое соответствующих регистров и повторить операцию, вызвавшую исключение. +* Некорректная инструкция и исключения-ловушки. Попытка выполнить инструкцию 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) для перехода с EL2 в EL3. +* Инструкции системных вызовов. Существуют инструкции, которые намерено генерируют исключение. Это инструкции используемые для реализации интерфейса вызова более привилегированного кода. Их часто называют инструкциями системных вызовов (system call). Такие инструкции позволяют выполнить переход между уровнями исключений: SVC (Supervisor Call) для перехода с EL0 в EL1, HVC (Hypervisor Call) для перехода с EL1 в EL2 и SMC (Secure Monitor Call) для перехода с EL1 или EL2 в EL3. -Что бы выполнить переход между уровнями исключений (который описан в предыдущем примере) существуют отдельные инструкции процессора: -* SVC (Supervisor Call) для перехода с EL0 в EL1, то есть, например, вызов ядра ОС из пользовательского приложения. -* HVC (Hypervisor Call) для перехода с EL1 в EL2, то есть, например, вызов гипервизора из ядра ОС. -* SMC (Secure Monitor Call) для перехода в EL3. Инструкцию можно использовать как с EL1 (например: ядро ОС), так и с EL2 (например: гипервизор). +Поскольку при обработке исключения уровень исключения не может уменьшаться, нельзя, например, вызвать инструкцию SVC с EL2 (из гипервизора), что бы попасть в EL1 (в ядро ОС). -Поскольку при обработке исключения уровень исключения не может уменьшаться, нельзя, например, вызвать инструкцию SVC с EL2 (например из гипервизора), что бы попасть в EL1 (например в ядро ОС). - ### Асинхронные (asynchronous) исключения -Некоторые исключения генерируются внешним источником, поэтому они не синхронны с текущим потоком исполняемых инструкций, например срабатывания таймера. По определению все исключения не являющиеся синхронными называются асинхронными. +Некоторые исключения генерируются внешним источником, поэтому они не синхронны с текущим потоком исполняемых инструкций (например: срабатывания таймера). По определению все исключения не являющиеся синхронными называются асинхронными. Более детальные примеры асинхронных исключений: * Системная ошибка (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 имеют одинаковый приоритет. @@ -132,7 +129,7 @@ Arm архитектура не имеет строг 🛈 В Armv7 и более ранних версиях PSTATE назывался CPSR и был реализован в виде регистра. -Для синхронных исключений и SError помимо прочего заполняется и регистр синдрома исключения (Exception Syndrome Register, ESR). В него записывается причина исключения. +Для синхронных исключений и SError помимо прочего заполняется и регистр синдрома исключения (Exception Syndrome Register, ESR). В нём кодируется причина исключения. ### Маршрутизация и контроллер прерываний @@ -141,20 +138,20 @@ Arm архитектура не имеет строг * Исключение маршрутизируется в соответствии с конфигурацией системных регистров. Маршрутизация задается независимо для 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). Он позволяет существенно снизить накладные расходы при виртуализации. Технические детали можно найти в техническом руководстве. 🛈 Нельзя перенаправлять исключение на нереализованный уровень исключений. Такое поведение является неопределенным (UNDEFINED). Так же нельзя возвращаться из исключения на отключенный или нереализованный уровень исключений. Попытка выполнения инструкции возврата приведет к возникновению ошибки. ### Маскирование (Masking) -Физические и виртуальные асинхронные исключения могут быть временно замаскированы. При этом исключения будут оставаться в ожидании начала обработки до момент, пока маска не будет снята. +Физические и виртуальные асинхронные исключения могут быть временно замаскированы. При этом исключения будут оставаться в ожидании начала обработки до момента, пока маска не будет снята. Синхронные исключения не могут быть замаскированы, так как они непосредственно связаны с текущей инструкцией и не могут быть отложены или проигнорированы. @@ -162,7 +159,7 @@ Arm архитектура не имеет строг В расширениях 2021 года, Armv8.8-A и Armv9.3-A, добавлена поддержка немаскируемых прерываний (Non-maskable interrupt, NMI). Если эта возможность включена, то такое прерывание может быть доставлено процессору несмотря на маски. -### Таблицы векторов (vector tables) AArch64 +### Таблицы векторов (vector tables) При принятии исключения процессор исполняет код обработчика исключения. Место в памяти, где хранится обработчик, называется вектором исключения. @@ -182,4 +179,25 @@ Arm архитектура не имеет строг * +0x100 - FIQ/vFIQ * +0x180 - SError/VSError -Непосредственно в векторе исключения умещаются 32 процессорных инструкции. Обычно код вектора исключения сохраняет в стеке содержимое регистров, которые могут быть изменены и вызывает функцию более сложного обработчика, специфичного для текущего исключения. После возврата содержимое регистров восстанавливается и вызывается инструкция возврата из исключения (ERET). +Непосредственно в векторе исключения умещаются 32 процессорных инструкции, которые так же называют обработчиком первого уровня. Обычно код вектора исключения сохраняет в стеке содержимое регистров, которые могут быть изменены и вызывает функцию более сложного обработчика, специфичного для текущего исключения. После возврата содержимое регистров восстанавливается и исполняется инструкция возврата из исключения (ERET). + +### Указатель стека при принятии исключения + +В AArch64 при принятии исключения можно выбрать один из двух регистров указателя стека: SP_EL0 или SP_EL, где - текущий уровень Exception. Если исполнение происходит на уровне EL0, то безусловно используется SP_EL0. Если текущий уровень исполнения выше чем 0, то указатель сетка определяется битом SP из PSTATE: +* Если PSTATE.SP равен 0, то используется SP_EL0. +* Если PSTATE.SP равен 1, то используется SP_ELx текущего уровня исключений. + +Обычно, даже если указатель стека выбран SP_ELx, обработчик исключения первого уровня сохраняет регистры, значение которых может быть изменено в результате обработки исключения, а затем всё равно переключается на использование SP_EL0. + +## Возврат из исключения + +Возврат из исключения осуществляется инструкцией ERET. Инструкция ERET восстанавливает предыдущее состояние процессора из соответствующего регистра SPSR_EL, где - уровень исключения, на котором выполняется обработчик исключения. А после инструкция передает управление на прерванную инструкцию, адрес которой сохранён в ELR. Оба действия (восстановление предыдущего состояния из SPSR_ELx и передача управления по адресу из ELR_ELx) выполняются атомарно. + +🛈 Обратите внимание, что состояние исполнения, указанное в SPSR_ELx должно быть согласовано с SCR_EL3.RW или HCR_EL2.RW + +Адрес возврата, сохранённый в ELR_ELx зависит от типа исключения: +* Для инструкций SVC, HMC и SMC регистр ELR будет указывать на следующую инструкцию. +* Для остальных синхронных исключений регистр ELR будет указывать на инструкцию, породившую исключение. +* Для асинхронных исключений регистр ELR будет указывать на следующую инструкцию после последней полностью выполненной инструкции. + +Обработчик исключения может менять ELR_ELx по своему усмотрению.