快速连接
👉👉👉【精选】ARMv8/ARMv9架构入门到精通-目录 👈👈👈
1、在linux中的异常向量表
(1)、arm64的异常向量表-(irq,fiq,svc......)
armv8-arch64架构下,linux kernel的异常量表,再entry.S中:
/*
* Exception vectors.
*/
.align 11
ENTRY(vectors)
kernel_ventry 1, sync_invalid // Synchronous EL1t
kernel_ventry 1, irq_invalid // IRQ EL1t
kernel_ventry 1, fiq_invalid // FIQ EL1t
kernel_ventry 1, error_invalid // Error EL1t
kernel_ventry 1, sync // Synchronous EL1h
kernel_ventry 1, irq // IRQ EL1h
kernel_ventry 1, fiq_invalid // FIQ EL1h
kernel_ventry 1, error_invalid // Error EL1h
kernel_ventry 0, sync // Synchronous 64-bit EL0
kernel_ventry 0, irq // IRQ 64-bit EL0
kernel_ventry 0, fiq_invalid // FIQ 64-bit EL0
kernel_ventry 0, error_invalid // Error 64-bit EL0
#ifdef CONFIG_COMPAT
kernel_ventry 0, sync_compat, 32 // Synchronous 32-bit EL0
kernel_ventry 0, irq_compat, 32 // IRQ 32-bit EL0
kernel_ventry 0, fiq_invalid_compat, 32 // FIQ 32-bit EL0
kernel_ventry 0, error_invalid_compat, 32 // Error 32-bit EL0
#else
kernel_ventry 0, sync_invalid, 32 // Synchronous 32-bit EL0
kernel_ventry 0, irq_invalid, 32 // IRQ 32-bit EL0
kernel_ventry 0, fiq_invalid, 32 // FIQ 32-bit EL0
kernel_ventry 0, error_invalid, 32 // Error 32-bit EL0
#endif
END(vectors)
我们这里讲解如下四行:
kernel_ventry 1, irq // IRQ EL1h
kernel_ventry 0, irq // IRQ 64-bit EL0
kernel_ventry 1, sync // Synchronous EL1h
kernel_ventry 0, sync // Synchronous 64-bit EL0
kernel_ventry是宏,翻译后的函数名分别是:
el1_irq
el0_riq
el1_sync
el0_sync
对应的函数入口我们就找到了,也就是说,当触发irq异常、或svc异常时会跳转到这几个函数中。
(2)、arm32的异常向量表-(irq,fiq,swi......)
在arch架构下,linux kernel的同步异常向量表__stubs_start 和 异步异常向量表__vectors_start,在entry-armv.S中:
.section .stubs, "ax", %progbits
__stubs_start:
@ This must be the first word
.word vector_swi
.section .vectors, "ax", %progbits
__vectors_start:
W(b) vector_rst
W(b) vector_und
W(ldr) pc, __vectors_start + 0x1000
W(b) vector_pabt
W(b) vector_dabt
W(b) vector_addrexcptn
W(b) vector_irq
W(b) vector_fiq
2、在optee中的异常向量表
optee中的异常向量表thread_excp_vect
其中el0_sync_a64和el0_sync_a32是同步异常处理函数,当执行svc指令是会调用该函数;
#define INV_INSN 0
.section .text.thread_excp_vect
.align 11, INV_INSN
FUNC thread_excp_vect , :
/* -----------------------------------------------------
* EL1 with SP0 : 0x0 - 0x180
* -----------------------------------------------------
*/
.align 7, INV_INSN
el1_sync_sp0:
store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3
b el1_sync_abort
check_vector_size el1_sync_sp0
.align 7, INV_INSN
el1_irq_sp0:
store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3
b elx_irq
check_vector_size el1_irq_sp0
.align 7, INV_INSN
el1_fiq_sp0:
store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3
b elx_fiq
check_vector_size el1_fiq_sp0
.align 7, INV_INSN
el1_serror_sp0:
b el1_serror_sp0
check_vector_size el1_serror_sp0
/* -----------------------------------------------------
* Current EL with SP1: 0x200 - 0x380
* -----------------------------------------------------
*/
.align 7, INV_INSN
el1_sync_sp1:
b el1_sync_sp1
check_vector_size el1_sync_sp1
.align 7, INV_INSN
el1_irq_sp1:
b el1_irq_sp1
check_vector_size el1_irq_sp1
.align 7, INV_INSN
el1_fiq_sp1:
b el1_fiq_sp1
check_vector_size el1_fiq_sp1
.align 7, INV_INSN
el1_serror_sp1:
b el1_serror_sp1
check_vector_size el1_serror_sp1
/* -----------------------------------------------------
* Lower EL using AArch64 : 0x400 - 0x580
* -----------------------------------------------------
*/
.align 7, INV_INSN
el0_sync_a64:
restore_mapping
mrs x2, esr_el1
mrs x3, sp_el0
lsr x2, x2, #ESR_EC_SHIFT
cmp x2, #ESR_EC_AARCH64_SVC
b.eq el0_svc
b el0_sync_abort
check_vector_size el0_sync_a64
.align 7, INV_INSN
el0_irq_a64:
restore_mapping
b elx_irq
check_vector_size el0_irq_a64
.align 7, INV_INSN
el0_fiq_a64:
restore_mapping
b elx_fiq
check_vector_size el0_fiq_a64
.align 7, INV_INSN
el0_serror_a64:
b el0_serror_a64
check_vector_size el0_serror_a64
/* -----------------------------------------------------
* Lower EL using AArch32 : 0x0 - 0x180
* -----------------------------------------------------
*/
.align 7, INV_INSN
el0_sync_a32:
restore_mapping
mrs x2, esr_el1
mrs x3, sp_el0
lsr x2, x2, #ESR_EC_SHIFT
cmp x2, #ESR_EC_AARCH32_SVC
b.eq el0_svc
b el0_sync_abort
check_vector_size el0_sync_a32
.align 7, INV_INSN
el0_irq_a32:
restore_mapping
b elx_irq
check_vector_size el0_irq_a32
.align 7, INV_INSN
el0_fiq_a32:
restore_mapping
b elx_fiq
check_vector_size el0_fiq_a32
.align 7, INV_INSN
el0_serror_a32:
b el0_serror_a32
check_vector_size el0_serror_a32
3、在ATF中的异常向量表
(1)、同步异常向量表-(smc)
smc同步异常调用的都是handle_sync_exception
sync_exception_aarch64:
/* -----------------------------------------------------
* This exception vector will be the entry point for
* SMCs and traps that are unhandled at lower ELs most
* commonly. SP_EL3 should point to a valid cpu context
* where the general purpose and system register state
* can be saved.
* -----------------------------------------------------
*/
handle_sync_exception
check_vector_size sync_exception_aarch64
sync_exception_aarch32:
/* -----------------------------------------------------
* This exception vector will be the entry point for
* SMCs and traps that are unhandled at lower ELs most
* commonly. SP_EL3 should point to a valid cpu context
* where the general purpose and system register state
* can be saved.
* -----------------------------------------------------
*/
handle_sync_exception
check_vector_size sync_exception_aarch32
handle_sync_exception调用smc_handler64处理同步异常
.macro handle_sync_exception
/* Enable the SError interrupt */
msr daifclr, #DAIF_ABT_BIT
str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
mrs x30, esr_el3
ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
cmp x30, #EC_AARCH32_SMC
b.eq smc_handler32
cmp x30, #EC_AARCH64_SMC
b.eq smc_handler64
/* -----------------------------------------------------
* The following code handles any synchronous exception
* that is not an SMC.
* -----------------------------------------------------
*/
bl report_unhandled_exception
.endm
(2)、异类步异常向量表-(irq,fiq...)
irq/fiq异步异常调用的是handle_interrupt_exception
irq_aarch64:
handle_interrupt_exception irq_aarch64
check_vector_size irq_aarch64
.align 7
fiq_aarch64:
handle_interrupt_exception fiq_aarch64
check_vector_size fiq_aarch64
get_interrupt_type_handler获取ATF注册的中断处理函数
interrupt_type_handler_t get_interrupt_type_handler(uint32_t type)
{
if (validate_interrupt_type(type))
return NULL;
return intr_type_descs[type].handler;
}
handle_interrupt_exception调用ATF中注册的handler函数
.macro handle_interrupt_exception label
/* Enable the SError interrupt */
msr daifclr, #DAIF_ABT_BIT
str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
bl save_gp_registers
/*
* Save the EL3 system registers needed to return from
* this exception.
*/
mrs x0, spsr_el3
mrs x1, elr_el3
stp x0, x1, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
/* Switch to the runtime stack i.e. SP_EL0 */
ldr x2, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
mov x20, sp
msr spsel, #0
mov sp, x2
/*
* Find out whether this is a valid interrupt type. If the
* interrupt controller reports a spurious interrupt then
* return to where we came from.
*/
bl plat_ic_get_pending_interrupt_type
cmp x0, #INTR_TYPE_INVAL
b.eq interrupt_exit_\label
/*
* Get the registered handler for this interrupt type. A
* NULL return value could be 'cause of the following
* conditions:
*
* a. An interrupt of a type was routed correctly but a
* handler for its type was not registered.
*
* b. An interrupt of a type was not routed correctly so
* a handler for its type was not registered.
*
* c. An interrupt of a type was routed correctly to EL3,
* but was deasserted before its pending state could
* be read. Another interrupt of a different type pended
* at the same time and its type was reported as pending
* instead. However, a handler for this type was not
* registered.
*
* a. and b. can only happen due to a programming error.
* The occurrence of c. could be beyond the control of
* Trusted Firmware. It makes sense to return from this
* exception instead of reporting an error.
*/
bl get_interrupt_type_handler
cbz x0, interrupt_exit_\label
mov x21, x0
mov x0, #INTR_ID_UNAVAILABLE
/* Set the current security state in the 'flags' parameter */
mrs x2, scr_el3
ubfx x1, x2, #0, #1
/* Restore the reference to the 'handle' i.e. SP_EL3 */
mov x2, x20
/* x3 will point to a cookie (not used now) */
mov x3, xzr
/* Call the interrupt type handler */
blr x21
interrupt_exit_\label:
/* Return from exception, possibly in a different security state */
b el3_exit
.endm
剖析该段汇编的关键代码:
bl get_interrupt_type_handler //获取注册的中断处理函数, 返回函数地址,保存在X0中
cbz x0, interrupt_exit_\label
mov x21, x0 //X0保存到了X21中
.....
blr x21 //跳转到X21,就是跳转到ATF中的中断处理函数
《ARMv8/ARMv9架构学习系列课程》全系列,共计51节课,超15h的视频课程
关注"Arm精选"公众号,备注进ARM交流讨论区。