文章目錄
-
-
-
- 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
然後我們剖析下,這個線程向量表位址記錄到哪裡去了?
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TP35ENBRlT6VkaNBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL5ITMxUTNyAjM4AzNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
可以看出,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);
}