[ARM异常]-linux中(aarch/aarch64)异常向量表介绍
文章目錄
- 1、ARM的異常向量表基地址寄存器--VBAR
- 1.1、armv8 : VBAR寄存器
- 1.2、armv7 : VBAR寄存器
- 2、ARM的異常向量表的定義
- 2.1 armv8 :異常向量表offset的定義
- 2.2 armv8 : 在linux kernel中異常向量表的實現(xiàn)定義
- 2.3 armv8 : 在ATF中異常向量表的實現(xiàn)定義
- 2.4 armv8 : 異常向量表總結(jié)和示例:
- 2.5 armv7 :異常向量表offset的定義
- 2.6 armv7 : 在linux kernel中異常向量表的實現(xiàn)定義
- 3、總結(jié):
★★★ 友情鏈接 : 個人博客導讀首頁—點擊此處 ★★★
1、ARM的異常向量表基地址寄存器–VBAR
1.1、armv8 : VBAR寄存器
1.2、armv7 : VBAR寄存器
2、ARM的異常向量表的定義
2.1 armv8 :異常向量表offset的定義
實際上有四組表,每組表有四個異常入口,分別對應(yīng)同步異常,IRQ,FIQ和出錯異常。
- 如果發(fā)生異常并不會導致exception level切換,并且使用的棧指針是SP_EL0,那么使用第一組異常向量表。
- 如果發(fā)生異常并不會導致exception level切換,并且使用的棧指針是SP_EL1/2/3,那么使用第二組異常向量表。
- 如果發(fā)生異常會導致exception level切換,并且比目的exception level低一級的exception
level運行在AARCH64模式,那么使用第三組異常向量表。 - 如果發(fā)生異常會導致exception level切換,并且比目的exception level低一級的exception
level運行在AARCH32模式,那么使用第四組異常向量表。
另外我們還可以看到的一點是,每一個異常入口不再僅僅占用4bytes的空間,而是占用0x80 bytes空間,也就是說,每一個異常入口可以放置多條指令,而不僅僅是一條跳轉(zhuǎn)指令
2.2 armv8 : 在linux kernel中異常向量表的實現(xiàn)定義
我們再來看在linux kernel中定義的異常向量表
.align 11 ENTRY(vectors) (1)kernel_ventry 1, sync_invalid // Synchronous EL1tkernel_ventry 1, irq_invalid // IRQ EL1tkernel_ventry 1, fiq_invalid // FIQ EL1tkernel_ventry 1, error_invalid // Error EL1t (2)kernel_ventry 1, sync // Synchronous EL1hkernel_ventry 1, irq // IRQ EL1hkernel_ventry 1, fiq_invalid // FIQ EL1hkernel_ventry 1, error_invalid // Error EL1h (3)kernel_ventry 0, sync // Synchronous 64-bit EL0kernel_ventry 0, irq // IRQ 64-bit EL0kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0kernel_ventry 0, error_invalid // Error 64-bit EL0 (4) #ifdef CONFIG_COMPATkernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0kernel_ventry 0, irq_compat, 32 // IRQ 32-bit EL0kernel_ventry 0, fiq_invalid_compat, 32 // FIQ 32-bit EL0kernel_ventry 0, error_invalid_compat, 32 // Error 32-bit EL0 #elsekernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0kernel_ventry 0, irq_invalid, 32 // IRQ 32-bit EL0kernel_ventry 0, fiq_invalid, 32 // FIQ 32-bit EL0kernel_ventry 0, error_invalid, 32 // Error 32-bit EL0 #endif END(vectors)第(1)段對應(yīng)的是第一行向量表、第(2)段對應(yīng)的是第二行向量表、第(3)段對應(yīng)的是第三行向量表、第四段對應(yīng)的是第一行向量表.
帶invalid后綴的,都是未實現(xiàn)的。然后我們抽出實現(xiàn)了的部分,僅4行:
他們對應(yīng)的函數(shù)分別是:
el1_sync //在kernel mode中調(diào)用svc指令,觸發(fā)同步異常
el1_irq //在kernel mode中觸發(fā)了irq異步異常
el0_sync //在user mode中調(diào)用svc指令,觸發(fā)同步異常
el0_irq //在user mode中觸發(fā)了irq異步異常
2.3 armv8 : 在ATF中異常向量表的實現(xiàn)定義
在ATF的代碼中,在不同的階段有著不同的異常向量表:
- 在bl1階段使用bl1_exceptions
- 在bl2階段使用bl2_entrypoint
- 在bl31及其之后使用runtime_exceptions
我們常說的ATF中的向量表,其實就是bl31之后使用runtime_exceptions向量表,下面重點介紹下
(注意 : 帶unhandled的都是未實現(xiàn)的)
- 用于處理EL0產(chǎn)生異常時的entire(對應(yīng)第一行向量表)
- 用于處理當前ELx產(chǎn)生異常時的entire(對應(yīng)第二行向量表)
- 用于處理AArch64指令產(chǎn)生的異常,且發(fā)生了EL的遷移的entire(對應(yīng)第三行向量表)
- 用于處理AArch32指令產(chǎn)生的異常,且發(fā)生了EL的遷移的entire(對應(yīng)第四行向量表)
2.4 armv8 : 異常向量表總結(jié)和示例:
以異步異常irq為例
(1)、當irq產(chǎn)生,如果該irq被target到了EL3,那么將使用VBAR_EL3寄存器中的基地址.
我們知道armv8有四組異常向量表,對應(yīng)表格四行。然后再看使用哪組表:
cpu運行在EL0時產(chǎn)生了irq, 切未發(fā)生EL級別切換(中斷需被target到EL0),使用第一組表,這個條件不會存在.
cpu是在EL3時產(chǎn)生的irq, 未發(fā)生EL級別切換,使用第二組表,跳轉(zhuǎn)到VBAR_EL3 + 0x280處,對應(yīng)的irq_sp_elx函數(shù)
cpu運行在aarch64級別,在EL1/EL2時產(chǎn)生的irq,發(fā)生了EL級別切換,使用第三組表,跳轉(zhuǎn)到VBAR_EL3 + 0x480處,對應(yīng)的irq_aarch64函數(shù)
cpu運行在aarch32級別,在EL1/EL2時產(chǎn)生的irq,發(fā)生了EL級別切換,使用第四組表,跳轉(zhuǎn)到VBAR_EL3 + 0x680處,對應(yīng)的irq_aarch32函數(shù)
(2)、當irq產(chǎn)生,如果該irq被target到了EL1,那么將使用VBAR_EL1寄存器中的基地址.
我們知道armv8有四組異常向量表,對應(yīng)表格四行。然后再看使用哪組表:
cpu運行在EL0時產(chǎn)生了irq, 切未發(fā)生EL級別切換(中斷需被target到EL0),使用第一組表,這個條件不會存在.
cpu是在EL1時產(chǎn)生的irq, 未發(fā)生EL級別切換,使用第二組表,跳轉(zhuǎn)到VBAR_EL1 + 0x280處,對應(yīng)的el1_irq函數(shù)
cpu運行在aarch64級別,在EL0時產(chǎn)生的irq,發(fā)生了EL級別切換,使用第三組表,跳轉(zhuǎn)到VBAR_EL1 + 0x480處,對應(yīng)的el0_irq函數(shù)
cpu運行在aarch32級別,在EL0時產(chǎn)生的irq,發(fā)生了EL級別切換,使用第四組表,跳轉(zhuǎn)到VBAR_EL1 + 0x680處,對應(yīng)的irq_invalid函數(shù),也就是未實現(xiàn)
2.5 armv7 :異常向量表offset的定義
2.6 armv7 : 在linux kernel中異常向量表的實現(xiàn)定義
.section .stubs, "ax", %progbits __stubs_start:@ This must be the first word.word vector_swi.section .vectors, "ax", %progbits __vectors_start:W(b) vector_rstW(b) vector_undW(ldr) pc, __vectors_start + 0x1000W(b) vector_pabtW(b) vector_dabtW(b) vector_addrexcptnW(b) vector_irqW(b) vector_fiq3、總結(jié):
1、在armv7下使用的是data abort、prefetch abort、undefined instruction,在armv8下使用的是SError.
2、在linux kernel中,armv7體系下均已實現(xiàn)data abort、prefetch abort、undefined instruction異常處理函數(shù),在linux kernel的armv8體系下,沒有實現(xiàn)SError異常處理
3、在linux kernel的armv8體系中,未實現(xiàn)fiq函數(shù)
4、
在armv7的向量表offset中,每一個異常入口都是占4 bytes,是這樣排的:0x1c 0x18 0x10 0x0c 0x08 0x04
在armv8的向量表offset中,每一個異常入口都是占0x80bytes,是這樣排的00 0x80 0x100 0x180 0x200 0x280…
那么我們在linux kernel中定義的向量表,是怎樣和上面的offset對應(yīng)上的?
5、在armv7中,VBAR是banked的,在linux/tee各有一份拷貝. 在armv7中,沒有g(shù)ic的cpu interface。所以armv7的芯片只能使用gicv2.
在gicv2中,FIQ表示安全中斷,給TEE用的,IRQ表示非安全中斷,給Linux用的.
- 當cpu在REE(linux)執(zhí)行時,來了一個非安全中斷(linux中斷、IRQ), 那么cpu陷入異常,跳轉(zhuǎn)到 "normal VBAR + irq offset“ 處, 也就是linux irq中斷處理函數(shù)
- 當cpu在REE(linux)執(zhí)行時,來了一個安全中斷(tee中斷、FIQ),那么cpu陷入異常,跳轉(zhuǎn)到 "normal VBAR + fiq offset“ 處,也就是linux fiq中斷處理函數(shù)
- 當cpu在TEE(tee)執(zhí)行時,來了一個安全中斷(TEE中斷、FIQ), 那么cpu陷入異常,跳轉(zhuǎn)到 "secure VBAR + fiq offset“ 處, 也就是tee irq中斷處理函數(shù)
- 當cpu在TEE(tee)執(zhí)行時,來了一個非安全中斷(linux中斷、irq),那么cpu陷入異常,跳轉(zhuǎn)到 "secure VBAR + irq offset“ 處,也就是tee fiq中斷處理函數(shù), 在該函數(shù)中會主動將cpu切換到linux進行處理.
6、如果在某一時刻,將發(fā)送給cpu0的IPI_RESCHEDULE(SGI=2)中斷屏蔽了,過了一會再恢復(fù). 這樣會對linux系統(tǒng)有影響嗎?
內(nèi)核的中斷屏蔽,是將cpu的PSTATE.I置0了。 local_disable_irq后,gic再產(chǎn)生的中斷,ARM Core不會去處理,也就不會清除gic寄存器中的中斷狀態(tài). 等到 local_enable_irq后, 該中斷還會再送給ARM Core. 所以這種情況中斷不會丟失…
所以在某一時刻屏蔽了IPI_RESCHEDULE,也只是屏蔽,也沒有去清gic中相關(guān)寄存器。所以等到恢復(fù)屏蔽后,應(yīng)該也不會丟中斷
總結(jié)
以上是生活随笔為你收集整理的[ARM异常]-linux中(aarch/aarch64)异常向量表介绍的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在linux kernel中netlin
- 下一篇: [ARM异常]-图解armv7/armv