05-异常模型
快速鏈接:
.
👉👉👉 個人博客筆記導讀目錄(全部) 👈👈👈
相關鏈接: (專題:《learn-the-architecture系列》)
- 01-Introducing the Arm architecture
- 02-Armv8-A Instruction Set Architecture
- 03_Introduction_to_AMBA_AXI
- 04-TrustZone for Armv8-A
- 05-Exception model
- 06-GICv3_v4_overview
- 07-Armv8-A virtualization
- 08-Isolation using virtualization in the Secure World_Whitepaper
- 09-LearnTheArchitecture-MemoryManagement
- 10-Armv8-A memory model guide–ongoing
- 11-Memory Management Examples
- 12-Generic Timer
- 13-Introduction to security
- 14-Providing protection for complex software
- 15-Arm-Confidential-Compute-Software-Stack
- 16-Understanding the Armv8.x extensions
目錄
- 1 簡介
- 2 特權和異常模型
- 2.1. 特權的類型
- 2.2. 內存特權
- 2.3. 寄存器的訪問
- 3 執行狀態和安全狀態
- 3.1. 執行狀態
- 3.2. 安全狀態
- 3.3. 執行狀態的改變
- 3.4. 安全狀態的改變
- 3.5. 實現定義的異常級別和執行狀態
- 4 異常類型
- 4.1. 同步異常
- 4.2. 異步異常
- 4.3. IRQ and FIQ
- 4.4. SError
- 5 Handling exceptions
- 5.1. Exception terminology
- 5.2. Taking an exception
- 5.3. Routing asynchronous exceptions
- 5.4. Determining which Execution state an exception is taken to
- 5.5. Returning from an exception
- 5.6. Exception stacks
- 6 The vector tables
1 簡介
本文介紹了 Armv8-A 中的異常和特權模型。 本文涵蓋了 Arm 架構中不同類型的異常,以及處理器在收到異常時的行為。本文適用于底層代碼的開發人員,例如引導代碼或驅動程序。 它與編寫代碼來設置或管理異常的任何人都特別相關。
2 特權和異常模型
在講解Armv8-A異常模型的細節之前,我們先來介紹一下特權的概念。 現代軟件期望被分成不同的模塊,每個模塊對系統和處理器資源的訪問級別不同。 這方面的一個例子是操作系統內核(具有對系統資源的高級訪問權限)和用戶應用程序訪問呢的系統資源是有限的。
Armv8-A 通過實現不同級別的權限來實現這種拆分。 當前權限級別只能在處理器接受或從異常中返回時更改。 因此,這些特權級別在 Armv8-A 架構中被稱為異常級別。 每個異常級別都有編號,特權級別越高,編號越大。
如下圖所示,異常級別稱為 EL,其中 x 為 0 到 3 之間的數字。例如,最低權限級別稱為 EL0。
一個常見的使用模型是應用程序代碼在 EL0 上運行,操作系統在 EL1 上運行。 EL2 由hypervisror使用,EL3 由TrustedFirmware使用。
注意:體系結構不強制執行此軟件模型,但標準軟件采用此模型。 出于這個原因,本文的其余部分假設了這種使用模型
2.1. 特權的類型
有兩種與此相關的特權。 第一個是內存系統中的特權,第二個是從訪問處理器資源的角度來看的特權。 兩者都受當前異常級別的影響。
2.2. 內存特權
Armv8-A 實現了一個虛擬內存系統,其中內存管理單元 (MMU) 允許軟件為內存區域分配屬性。 這些屬性包括讀/寫權限,可以配置兩個自由度。 此配置允許特權和非特權訪問的單獨訪問權限。
當處理器在 EL0 中執行時啟動的內存訪問將根據非特權訪問權限進行檢查。 來自 EL1、EL2 和 EL3 的內存訪問將根據特權訪問權限進行檢查。
由于此內存配置是由軟件使用 MMU 的轉換表編程的,因此您應該考慮對這些表進行編程所需的特權。 MMU 配置存儲在系統寄存器中,訪問這些寄存器的能力也受當前異常級別控制。
2.3. 寄存器的訪問
Armv8-A 處理器的配置設置保存在一系列稱為系統寄存器的寄存器中。 系統寄存器中的設置組合定義了當前的處理器上下文。 對系統寄存器的訪問由當前異常級別控制
系統寄存器的名稱表示可以訪問該寄存器的最低異常級別。 例如,TTBR0_EL1 是保存 EL0 和 EL1 使用的轉換表的基地址的寄存器。 無法從 EL0 訪問該寄存器,任何嘗試這樣做都會導致生成異常。
該體系結構有許多具有概念上相似功能的寄存器,它們的名稱僅在異常級別后綴上有所不同。 這些是獨立的、單獨的寄存器,在指令集中有自己的編碼,并將在硬件中單獨實現。 例如,以下寄存器都為不同的轉換機制執行 MMU 配置。 寄存器具有相似的名稱以反映它們執行相似的任務,但它們是完全獨立的寄存器,具有自己的訪問語義:
- SCTLR_EL1 – Top level system control for EL0 and EL1
- SCTLR_EL2 – Top level system control for EL2
- SCTLR_EL3 – Top level system control for EL3
注意:EL1 和 EL0 共享相同的 MMU 配置,并且控制僅限于在 EL1 上運行的特權代碼。 因此,沒有 SCTLR_EL0,所有控制都來自 EL1 可訪問寄存器。 其他控制寄存器通常遵循此模型。
較高的異常級別有權訪問控制較低級別的寄存器。 例如,EL2 有權在必要時訪問 SCTLR_EL1。 在系統的一般操作中,特權異常級別通常會控制自己的配置。 然而,更高的特權級別有時會訪問與較低異常級別相關聯的寄存器,例如,實現虛擬化功能或在上下文切換或電源管理操作期間作為保存和恢復操作的一部分讀取和寫入寄存器集。
3 執行狀態和安全狀態
Armv8-A 處理器的當前狀態由異常級別和其他兩個重要狀態決定。 當前執行狀態定義了通用寄存器的標準寬度和可用指令集。執行狀態也會影響內存模型的各個方面以及如何管理異常。
當前安全狀態控制當前有效的異常級別、當前可以訪問的內存區域以及這些訪問在系統內存總線上的表示方式。
下圖顯示了異常級別和安全狀態,使用了不同的執行狀態:
3.1. 執行狀態
Armv8-A提供兩種執行狀態:
- AArch32: The 32-bit Execution state. Operation in this state is compatible with Armv7-A. There are two available instruction sets: T32 and A32. The standard register width is 32 bits.
- AArch64: The 64-bit Execution state. There is one available instruction set: A64. The standard register width is 64 bits
3.2. 安全狀態
Armv8-A 架構允許實現兩種安全狀態。 這允許進一步劃分軟件以隔離和劃分受信任的軟件。
這兩種安全狀態是:
- Secure state
在這種狀態下,處理元件 (PE) 可以訪問安全和非安全物理地址空間。 在這種狀態下,PE 可以訪問安全和非安全系統寄存器。 在此狀態下運行的軟件只能確認安全中斷。 - Non-secure state
在這種狀態下,PE 只能訪問非安全物理地址空間。 PE 也只能訪問允許非安全訪問的系統寄存器。 在此狀態下運行的軟件只能確認非安全中斷
3.3. 執行狀態的改變
PE 只能在reset或異常級別更改時更改執行狀態.
復位時的執行狀態由 IMPLEMENTATION DEFINED 機制確定。 一些實現修復了重置時的執行狀態。 例如,Cortex-A32 將始終重置為 AArch32 狀態。 在 Armv8-A 的大多數實現中,復位后的執行狀態由在復位時采樣的信號控制。 這允許在片上系統級別控制復位執行狀態。
當 PE 在 Exception 級別之間發生變化時,也可以更改 Execution 狀態。 AArch32 和 AArch64 之間的轉換只允許遵守某些規則
- 當從較低的異常級別移動到較高級別時,執行狀態可以保持不變或更改為 AArch64
- 當從較高的異常級別移動到較低級別時,執行狀態可以保持不變或更改為 AArch32。
將這兩個規則放在一起意味著 64 位之上可以允許 32 位,但反過來不行。 例如,64 位操作系統內核可以同時托管 64 位和 32 位應用程序,而 32 位操作系統內核只能托管 32 位應用程序。
在此示例中,我們使用了操作系統和應用程序,但相同的規則適用于所有異常級別。 例如,EL2 的 32 位虛擬機管理程序只能托管 EL1 的 32 位虛擬機
3.4. 安全狀態的改變
EL3 始終被視為在安全狀態下執行。 使用 SCR_EL3,EL3 代碼可以更改所有較低異常級別的安全狀態。 如果軟件使用 SCR_EL3 更改較低異常級別的安全狀態,則 PE 將不會更改安全狀態,直到它更改為較低的異常級別。
3.5. 實現定義的異常級別和執行狀態
Armv8-A 架構允許實現選擇是否實現所有異常級別,并為每個實現的異常級別選擇允許哪些執行狀態
EL0 和 EL1 是唯一必須實現的異常級別。 EL2 和 EL3 是可選的。 選擇不實施 EL3 或 EL2 具有重要意義
EL3 是唯一可以更改安全狀態的級別。 如果實現選擇不實現 EL3,則該 PE 將無法訪問單個安全狀態
同樣,EL2 包含許多虛擬化功能。 沒有 EL2 的實現可以訪問這些功能。 該架構的所有當前 Arm 實現都實現了所有異常級別,如果沒有所有異常級別,就不可能使用大多數標準軟件
實現還可以選擇對每個異常級別有效的執行狀態。 如果在異常級別允許使用 AArch32,則必須允許所有較低的異常級別。 例如,如果 EL3 允許 AArch32,那么它必須在所有較低的異常級別上都允許
許多實現允許所有執行狀態和所有異常級別,但存在有限制的現有實現。 例如,Cortex-A32 只允許任何異常級別的 AArch32
一些現代實現,例如 Cortex-A55,實現了所有異常級別,但只允許 AArch32 在 EL0。(例如可參考這篇文章:Cortex-A76僅EL0支持aarch32) 其他異常級別 EL1、EL2 和 EL3 必須是 AArch64.
4 異常類型
異常是可以導致當前正在執行的程序被掛起并導致狀態發生變化以執行代碼來處理該異常的任何事件。 其他處理器架構可能將此描述為中斷。 在 Armv8-A 架構中,中斷是一種外部產生的異常。 Armv8-A 架構將異常分為兩大類:同步異常和異步異常。
4.1. 同步異常
同步異常是可能由剛剛執行的指令引起或與之相關的異常。 這意味著同步異常與執行流同步。
嘗試執行無效指令可能會導致同步異常,無論是當前異常級別不允許的指令還是已禁用的指令。
由于地址未對齊或 MMU 權限檢查之一失敗,內存訪問也可能導致同步異常。 由于這些錯誤是同步的,因此可以在嘗試訪問內存之前發生異常。 內存訪問也可以產生異步異常,這將在本節中討論。 內存管理指南中更詳細地討論了內存訪問錯誤。
Armv8-A 架構有一系列異常生成指令:SVC、HVC 和 SMC。 這些指令不同于簡單的無效指令,因為它們針對不同的異常級別,并且在對異常進行優先級排序時被區別對待。 這些指令用于實現系統調用接口,以允許較低特權的代碼從較高特權的代碼請求服務。
Debug exceptions也是同步異常
4.2. 異步異常
某些類型的異常是在外部生成的,因此與當前指令流不同步。 這意味著無法準確保證何時會發生異步異常。 Armv8-A 架構只要求它在有限的時間內發生。 異步異常也可以暫時屏蔽。 這意味著在發生異常之前,異步異常可以處于掛起狀態。
異步異常的種類有:
Physical interrupts
? SError (System Error)
? IRQ
? FIQ
Virtual Interrupts
? vSError (Virtual System Error)
? vIRQ (Virtual IRQ)
? vFIQ (Virtual FIQ)
物理中斷是響應于 PE 外產生的信號而產生的。 虛擬中斷可以由外部產生,也可以由在EL2執行的軟件產生。
4.3. IRQ and FIQ
Armv8-A 架構有兩種異常類型,IRQ 和 FIQ,旨在用于生成外設中斷。 在其他版本的 Arm 架構中,FIQ 被用作更高優先級的快速中斷。 這與 Armv8-A 不同,其中FIQ 與 IRQ 具有相同的優先級。
IRQ 和 FIQ 具有獨立的路由控制,通常用于實現安全和非安全中斷,如通用中斷控制器指南中所述
4.4. SError
SError 是一種異常類型,旨在由內存系統生成以響應錯誤的內存訪問。 SError 的典型用途是以前稱為外部的異步中止,例如已通過所有 MMU 檢查但在內存總線上遇到錯誤的內存訪問。 這可能會被異步報告,因為該指令可能已經退出。 SError 中斷也可能由某些 RAM 上的奇偶校驗或糾錯碼 (ECC) 檢查引起,例如內置緩存中的那些。
5 Handling exceptions
當發生異常時,當前程序流程被中斷。 處理元素 (PE) 將更新當前狀態并分支到向量表中的某個位置。 通常這個位置將包含通用代碼,用于將當前程序的狀態推送到堆棧上,然后分支到進一步的代碼。
5.1. Exception terminology
識別出異常時處理器所處的狀態稱為taken from 。 異常發生后 PE 立即所處的狀態是taken to。 例如,可以從 AArch32 EL0 到 AArch64 EL1 進行異常處理。
Armv8-A 架構具有觸發異常返回的指令。 在那種情況下,執行該指令時 PE 所處的狀態就是return from。 異常返回指令執行后的狀態就是return to
每個異常類型都針對一個異常級別。 異步異常可以路由到不同的異常級別。
5.2. Taking an exception
當發生異常時,必須保留當前狀態以便可以返回。 PE 會自動保存異常返回地址和當前 PSTATE
存儲在通用寄存器中的狀態必須由軟件保存。 PE 然后將當前 PSTATE 更新為架構中為該異常類型定義的 PSTATE,并跳轉到向量表中的異常處理程序。
發生異常的taken from的PSTATE 存儲在系統寄存器 SPSR_ELx 中,其中 是taken to的編號。 異常返回地址存儲在 ELR_ELx 中,其中 是taken to的編號。
5.3. Routing asynchronous exceptions
三種物理中斷類型可以獨立路由到特權異常級別之一,EL1、EL2 或 EL3。 下圖以 IRQ 為例:
此路由是使用 SCR_EL3 和 HCR_EL2 配置的。 使用 SCR_EL3 進行的路由配置將覆蓋使用 HCR_EL2 進行的路由配置。 這些控件允許將不同的中斷類型路由到不同的軟件。
路由到比正在執行的級別更低的異常級別的異常被隱式屏蔽。 異常將被掛起,直到 PE 更改為等于或低于路由到的異常級別
5.4. Determining which Execution state an exception is taken to
異常被采取的異常級別的執行狀態由更高的異常級別確定。 假設實現了所有異常級別,下表顯示了如何確定執行狀態:
5.5. Returning from an exception
軟件可以通過執行來自 AArch64 的 ERET 指令來啟動從異常返回。 這將導致根據 SPSR_ELx 的值配置返回的異常級別,其中 是從中返回的級別。 SPSR_ELx 包含要返回的目標級別和目標執行狀態。
注意 SPSR_ELx 中指定的 Execution state 必須與 SCR_EL3.RW 或 HCR_EL2.RW 中的配置匹配,否則會產生非法異常返回。
執行 ERET 指令時,狀態將從 SPSR_ELx 恢復,PC將更新為 ELR_ELx 中的值。 這兩個更新將以原子方式且不可分割地執行,以便 PE 不會處于未定義狀態。
5.6. Exception stacks
在 AArch64 中執行時,該架構允許選擇兩個堆棧指針寄存器; SP_EL0 或 SP_ELx,其中 是當前異常級別。 例如,在 EL1 可以選擇 SP_EL0 或 SP_EL1.
在一般執行期間,預計所有代碼都使用 SP_EL0。 發生異常時,最初選擇 SP_ELx。 這允許為初始異常處理維護單獨的堆棧。 這對于在處理由堆棧溢出引起的異常時維護有效堆棧很有用。
6 The vector tables
在 Armv8-A 中,向量表是包含指令的普通內存區域。 處理器元素 (PE) 將表的基地址保存在系統寄存器中,并且每個異常類型都具有一個相對于該基址的定義偏移量。
每個特權異常級別都有自己的向量表,由向量基地址寄存器 VBAR_ELx 定義,其中 是 1,2 或 3。
VBAR 寄存器的值在復位后未定義,因此必須在啟用中斷之前對其進行配置.
向量表的格式如下所示:
每種異常類型都可以導致跳轉到四個位置之一,具體取決于從中獲取異常的taken form的狀態。
總結
- 上一篇: 03_Introduction_to_A
- 下一篇: 06-GICv3_v4_overview