optee3.14中的异常向量表解读--中断处理解读
optee3.14中的異常向量表、VBAR_EL1、中斷實現的介紹
★★★ 個人博客導讀首頁—點擊此處 ★★★
.
說明:
在默認情況下,本文講述的都是ARMV8-aarch64架構,optee3.14版本, 未開啟FF-A
文章目錄
- 1、armv8-aarch64的異常向量表介紹
- 2、armv8的VBAR_ELx寄存器
- 3、optee異常向量表的實現
- 4、optee異常向量表基地址的定義
- 5、elx_irq和elx_fiq
1、armv8-aarch64的異常向量表介紹
我們可以看出,實際上有四組表,每組表有四個異常入口,分別對應同步異常,IRQ,FIQ和serror。
- 如果發生異常后并沒有exception level切換,并且發生異常之前使用的棧指針是SP_EL0,那么使用第一組異常向量表。
- 如果發生異常后并沒有exception level切換,并且發生異常之前使用的棧指針是SP_EL1/2/3,那么使用第二組異常向量表。
- 如果發生異常導致了exception level切換,并且發生異常之前的exception
level運行在AARCH64模式,那么使用第三組異常向量表。 - 如果發生異常導致了exception level切換,并且發生異常之前的exception
level運行在AARCH32模式,那么使用第四組異常向量表。
另外我們還可以看到的一點是,每一個異常入口不再僅僅占用4bytes的空間,而是占用0x80 bytes空間,也就是說,每一個異常入口可以放置多條指令,而不僅僅是一條跳轉指令
2、armv8的VBAR_ELx寄存器
armv8定義了VBAR_EL1、VBAR_EL2、VBAR_EL3三個基地址寄存器
3、optee異常向量表的實現
(optee_os/core/arch/arm/kernel/thread_a64.S)#define INV_INSN 0 FUNC thread_excp_vect , : align=2048/* -----------------------------------------------------* EL1 with SP0 : 0x0 - 0x180* -----------------------------------------------------*/.balign 128, INV_INSN el1_sync_sp0:store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3b el1_sync_abortcheck_vector_size el1_sync_sp0.balign 128, INV_INSN el1_irq_sp0:store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3b elx_irqcheck_vector_size el1_irq_sp0.balign 128, INV_INSN el1_fiq_sp0:store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3b elx_fiqcheck_vector_size el1_fiq_sp0.balign 128, INV_INSN el1_serror_sp0:b el1_serror_sp0check_vector_size el1_serror_sp0/* -----------------------------------------------------* Current EL with SP1: 0x200 - 0x380* -----------------------------------------------------*/.balign 128, INV_INSN el1_sync_sp1:b el1_sync_sp1check_vector_size el1_sync_sp1.balign 128, INV_INSN el1_irq_sp1:b el1_irq_sp1check_vector_size el1_irq_sp1.balign 128, INV_INSN el1_fiq_sp1:b el1_fiq_sp1check_vector_size el1_fiq_sp1.balign 128, INV_INSN el1_serror_sp1:b el1_serror_sp1check_vector_size el1_serror_sp1/* -----------------------------------------------------* Lower EL using AArch64 : 0x400 - 0x580* -----------------------------------------------------*/.balign 128, INV_INSN el0_sync_a64:restore_mappingmrs x2, esr_el1mrs x3, sp_el0lsr x2, x2, #ESR_EC_SHIFTcmp x2, #ESR_EC_AARCH64_SVCb.eq el0_svcb el0_sync_abortcheck_vector_size el0_sync_a64.balign 128, INV_INSN el0_irq_a64:restore_mappingb elx_irqcheck_vector_size el0_irq_a64.balign 128, INV_INSN el0_fiq_a64:restore_mappingb elx_fiqcheck_vector_size el0_fiq_a64.balign 128, INV_INSN el0_serror_a64:b el0_serror_a64check_vector_size el0_serror_a64/* -----------------------------------------------------* Lower EL using AArch32 : 0x0 - 0x180* -----------------------------------------------------*/.balign 128, INV_INSN el0_sync_a32:restore_mappingmrs x2, esr_el1mrs x3, sp_el0lsr x2, x2, #ESR_EC_SHIFTcmp x2, #ESR_EC_AARCH32_SVCb.eq el0_svcb el0_sync_abortcheck_vector_size el0_sync_a32.balign 128, INV_INSN el0_irq_a32:restore_mappingb elx_irqcheck_vector_size el0_irq_a32.balign 128, INV_INSN el0_fiq_a32:restore_mappingb elx_fiqcheck_vector_size el0_fiq_a32.balign 128, INV_INSN el0_serror_a32:b el0_serror_a32check_vector_size el0_serror_a32(1)、check_vector_size
check_vector_size其實就是檢查異常向量中的指令size,不能草果32*4=128字節,因為armv8-arch64定義的異常向量每一個offset中的地址范圍是128字節
(2)、128字節對其的異常向量
balign 128就是告訴匯編代碼,接下來的函數定義是128字節對其的。這也和armv8-arch64定義的異常向量的地址范圍一致
(3)、異常向量實現的總結
| 第一組 | el1_sync_sp0 | b el1_sync_abort | Y |
| 第一組 | el1_irq_sp0 | b elx_irq | Y |
| 第一組 | el1_fiq_sp0 | b elx_fiq | Y |
| 第一組 | el1_serror_sp0 | b el1_serror_sp0 自己跳轉到自己,相當于死循環 | N |
| 第二組 | el1_sync_sp1 | b el1_sync_sp1 自己跳轉到自己,相當于死循環 | N |
| 第二組 | el1_irq_sp1 | b el1_irq_sp1 自己跳轉到自己,相當于死循環 | N |
| 第二組 | el1_fiq_sp1 | b el1_fiq_sp1 自己跳轉到自己,相當于死循環 | N |
| 第二組 | el1_serror_sp1 | b el1_serror_sp1 自己跳轉到自己,相當于死循環 | N |
| 第三組 | el0_sync_a64 | b el0_sync_abort | Y |
| 第三組 | el0_irq_a64 | b elx_irq | Y |
| 第三組 | el0_fiq_a64 | b elx_fiq | Y |
| 第三組 | el0_serror_a64 | b el0_serror_a64 自己跳轉到自己,相當于死循環 | N |
| 第四組 | el0_sync_a32 | b el0_svc | Y |
| 第四組 | el0_irq_a32 | b elx_irq | Y |
| 第四組 | el0_fiq_a32 | b elx_fiq | Y |
| 第四組 | el0_serror_a32 | b el0_serror_a32 自己跳轉到自己,相當于死循環 | N |
總結一下也是很好理解:
- 在optee os中,使用的sp_el0棧,同時支持aarch32、aarch64的user程序,所以實現了第一、三、四組異常向量,另外optee不處理serror異常,所以serror也不實現。
- 在Linux kernel中,使用sp_el1棧,同時支持aarch32、aarch64的user程序,所以實現了第二、三、四組異常向量.
(注:雖然Linux Kernel實現了FIQ向量,但該向量下的邏輯最終跳轉到panic()函數,也就是如果觸發了target到Linux Kernel的FIQ,將發生panic.)
(4)、elx_irq和elx_fiq
以irq/fiq為例,我們還可以發現,無論是哪種分組異常,最終跳轉的都是同一類函數:elx_irq和elx_fiq,即無論是下面哪種情況,跳轉的都是elx_irq和elx_fiq函數。
- PE在optee os特權級(S-EL1)執行時,來了一個irq/fiq中斷
- PE在userspace非特權級(S-EL0)執行aarch64時,來了一個irq/fiq中斷
- PE在userspace非特權級(S-user mode)執行aarch32時,來了一個irq/fiq中斷
4、optee異常向量表基地址的定義
從上文的異常向量表的實現中可以發現,異常向量定義在了thread_excp_vect函數中, 那么該函數(異常向量)是如何布局到內存的? 該函數的基地址又是如何寫入到VBAR_EL1的?
FUNC thread_excp_vect , : align=2048
thread_init_vbar(vaddr_t addr)將addr寫入到vbar_el1
get_excp_vect()返回異常向量表基地址(當然是虛擬地址)
(optee_os/core/arch/arm/kernel/thread.c)static vaddr_t get_excp_vect(void) { #ifdef CFG_CORE_WORKAROUND_SPECTRE_BP_SECuint32_t midr = read_midr();if (get_midr_implementer(midr) != MIDR_IMPLEMENTER_ARM)return (vaddr_t)thread_excp_vect;switch (get_midr_primary_part(midr)) { #ifdef ARM32case CORTEX_A8_PART_NUM:case CORTEX_A9_PART_NUM:case CORTEX_A17_PART_NUM: #endifcase CORTEX_A57_PART_NUM:case CORTEX_A72_PART_NUM:case CORTEX_A73_PART_NUM:case CORTEX_A75_PART_NUM:return select_vector((vaddr_t)thread_excp_vect_workaround); #ifdef ARM32case CORTEX_A15_PART_NUM:return select_vector((vaddr_t)thread_excp_vect_workaround_a15); #endifdefault:return (vaddr_t)thread_excp_vect;} #endif /*CFG_CORE_WORKAROUND_SPECTRE_BP_SEC*/return (vaddr_t)thread_excp_vect; }關于從cpu的啟動(從cpu啟動時設置VBAR_EL1):
- 如果在整個系統中有實現ATF,則CFG_WITH_ARM_TRUSTED_FW宏是打開的,那么從cpu是從boot_cpu_on_handler啟動,也就是從ATF調來的。
- 如果在整個系統中沒有實現ATF,則CFG_WITH_ARM_TRUSTED_FW宏是關閉的,那么從cpu是從reset_secondary---->boot_init_secondary調用過來的
細心的同學看代碼可以發現:
- armv8-aarch64架構都是有實現ATF,一般情況下CFG_WITH_ARM_TRUSTED_FW宏也都是打開的
- 在optee的aarch64體系中,是沒有調用boot_init_secondary函數的,僅僅在optee_os/core/arch/arm/kernel/entry_a32.S中的reset_secondary中進行了調用boot_init_secondary()
5、elx_irq和elx_fiq
gicv3/gicv2有著不同的處理
- 如果是gicv2,則會將irq視為外系統中斷,fiq視為本系統中斷;
- 如果是gicv3,恰好相反,將fiq視為外系統中斷,irq視為本系統中斷.
(注從optee中斷軟件的視角來看,gic可以分為兩類,gicv2、非gicv2, 這里說說的gicv3其實就是非gicv2,如果你使用的是gicv4,那么也會定義CFG_ARM_GICV3宏)
本系統中斷和外部系統中斷的處理:
- 如果是本系統中斷,則調用native_intr_handler
- 如果是外部系統中斷則調用foreign_intr_handler
總結
以上是生活随笔為你收集整理的optee3.14中的异常向量表解读--中断处理解读的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 探究实现中断下半部分的第四种方式
- 下一篇: optee中添加一个中断以及底层代码的相