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的视频课程

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐