天天看点

optee中的thread_vector_table线程向量表

文章目录

        • 1、向量表的定义
        • 2、向量表的注册

★★★ 友情链接 : 个人博客导读首页—点击此处 ★★★

1、向量表的定义

在thread_a64.S中:

/*
 * Vector table supplied to ARM Trusted Firmware (ARM-TF) at
 * initialization.
 *
 * Note that ARM-TF depends on the layout of this vector table, any change
 * in layout has to be synced with ARM-TF.
 */
FUNC thread_vector_table , :
	b	vector_std_smc_entry
	b	vector_fast_smc_entry
	b	vector_cpu_on_entry
	b	vector_cpu_off_entry
	b	vector_cpu_resume_entry
	b	vector_cpu_suspend_entry
	b	vector_fiq_entry
	b	vector_system_off_entry
	b	vector_system_reset_entry
END_FUNC thread_vector_table
KEEP_PAGER thread_vector_table
           

这个向量表地址,会被传到ATF中,保存在全局变量中

2、向量表的注册

在optee初始化时,generic_boot_init_primary函数获取该向量表的地址:

struct thread_vector_table *
generic_boot_init_primary(unsigned long pageable_part, unsigned long u __unused,
			  unsigned long fdt)
{
	init_primary_helper(pageable_part, PADDR_INVALID, fdt);
	return &thread_vector_table;
}
           

_start函数调用的generic_boot_init_primary

FUNC _start , :
	mov	x19, x0		/* Save pagable part address */
	mov	x20, x2		/* Save DT address */

	adr	x0, reset_vect_table
	msr	vbar_el1, x0
	isb

	set_sctlr_el1
	isb

#ifdef CFG_WITH_PAGER
	/*
	 * Move init code into correct location and move hashes to a
	 * temporary safe location until the heap is initialized.
	 *
	 * The binary is built as:
	 * [Pager code, rodata and data] : In correct location
	 * [Init code and rodata] : Should be copied to __init_start
	 * [Hashes] : Should be saved before initializing pager
	 *
	 */
	adr	x0, __init_start	/* dst */
	adr	x1, __data_end		/* src */
	adr	x2, __tmp_hashes_end	/* dst limit */
	/* Copy backwards (as memmove) in case we're overlapping */
	sub	x2, x2, x0		/* len */
	add	x0, x0, x2		/* __init_start + len = __init_end */
	add	x1, x1, x2		/* __data_end + len */
	adr	x2, __init_start
copy_init:
	ldp	x3, x4, [x1, #-16]!
	stp	x3, x4, [x0, #-16]!
	cmp	x0, x2
	b.gt	copy_init
#endif

	/*
	 * Clear .bss, this code obviously depends on the linker keeping
	 * start/end of .bss at least 8 byte aligned.
	 */
	adr_l	x0, __bss_start
	adr_l	x1, __bss_end
clear_bss:
	str	xzr, [x0], #8
	cmp	x0, x1
	b.lt	clear_bss

	/* Setup SP_EL0 and SP_EL1, SP will be set to SP_EL0 */
	set_sp

	/* Enable aborts now that we can receive exceptions */
	msr	daifclr, #DAIFBIT_ABT

	adr_l	x0, __text_start
#ifdef CFG_WITH_PAGER
	adrp	x1, __tmp_hashes_end
	add	x1, x1, :lo12:__tmp_hashes_end
#else
	adrp	x1, __end
	add	x1, x1, :lo12:__end
#endif
	sub	x1, x1, x0
	bl	dcache_inv_range

	/* Enable Console */
	bl	console_init

	bl	core_init_mmu_map
	bl	core_init_mmu_regs
	bl	cpu_mmu_enable
	bl	cpu_mmu_enable_icache
	bl	cpu_mmu_enable_dcache

	mov	x0, x19		/* pagable part address */
	mov	x1, #-1
	mov	x2, x20		/* DT address */
	bl	generic_boot_init_primary

	/*
	 * In case we've touched memory that secondary CPUs will use before
	 * they have turned on their D-cache, clean and invalidate the
	 * D-cache before exiting to normal world.
	 */
	mov	x19, x0
	adr_l	x0, __text_start
#ifdef CFG_WITH_PAGER
	adrp	x1, __tmp_hashes_end
	add	x1, x1, :lo12:__tmp_hashes_end
#else
	adrp	x1, __end
	add	x1, x1, :lo12:__end
#endif
	sub	x1, x1, x0
	bl	dcache_cleaninv_range


	/*
	 * Clear current thread id now to allow the thread to be reused on
	 * next entry. Matches the thread_init_boot_thread in
	 * generic_boot.c.
	 */
	bl 	thread_clr_boot_thread

	/* Pass the vector address returned from main_init */
	mov	x1, x19
	mov	x0, #TEESMC_OPTEED_RETURN_ENTRY_DONE
	smc	#0
	b	.	/* SMC should not return */
END_FUNC _start
KEEP_INIT _start
           

然后我们剖析下,这个线程向量表地址记录到哪里去了?

optee中的thread_vector_table线程向量表

可以看出,optee读取到线程向量表后,将该地址放到X1参数中,然后调用smc切换到ATF

在ATF中,我们看opteed_smc_handler()函数,有如下片段,我们可以看到,在optee初始化完毕后,将线程量表表保存到X1中,然后调用smc(cmd=TEESMC_OPTEED_RETURN_ENTRY_DONE)切回到ATF,ATF中将该向量表保存到全局变量中optee_vectors

switch (smc_fid) {
/*
 * OPTEE has finished initialising itself after a cold boot
 */
case TEESMC_OPTEED_RETURN_ENTRY_DONE:
	/*
	 * Stash the OPTEE entry points information. This is done
	 * only once on the primary cpu
	 */
	assert(optee_vectors == NULL);
	optee_vectors = (optee_vectors_t *) x1;

	if (optee_vectors) {
		set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON);

		/*
		 * OPTEE has been successfully initialized.
		 * Register power management hooks with PSCI
		 */
		psci_register_spd_pm_hook(&opteed_pm);

		/*
		 * Register an interrupt handler for S-EL1 interrupts
		 * when generated during code executing in the
		 * non-secure state.
		 */
		flags = 0;
		set_interrupt_rm_flag(flags, NON_SECURE);
		rc = register_interrupt_type_handler(INTR_TYPE_S_EL1,
					opteed_sel1_interrupt_handler,
					flags);
		if (rc)
			panic();
	}

	/*
	 * OPTEE reports completion. The OPTEED must have initiated
	 * the original request through a synchronous entry into
	 * OPTEE. Jump back to the original C runtime context.
	 */
	opteed_synchronous_sp_exit(optee_ctx, x1);
           

当从REE—>ATF—>TEE流程时,在ATF中其实就是跳转到的optee_vector表中指向的函数

if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_FAST) {
	cm_set_elr_el3(SECURE, (uint64_t)
			&optee_vectors->fast_smc_entry);
} else {
	cm_set_elr_el3(SECURE, (uint64_t)
			&optee_vectors->std_smc_entry);
}
           

继续阅读