在optee的初始化时会调用 thread_init_per_cpu
void thread_init_per_cpu(void)
{
size_t pos = get_core_pos();
struct thread_core_local *l = thread_get_core_local();
init_sec_mon(pos);
set_tmp_stack(l, GET_STACK(stack_tmp[pos]) - STACK_TMP_OFFS);
set_abt_stack(l, GET_STACK(stack_abt[pos]));
thread_init_vbar();
}
在thread_init_per_cpu 中最重要的是调用thread_init_vbar来保存中断向量表
FUNC thread_init_vbar , :
adr x0, thread_vect_table
msr vbar_el1, x0
ret
END_FUNC thread_init_vbar
可以看到在thread_init_vbar 中是将thread_vect_table 保存到vbar_el1 中,这里的thread_vect_table 就是中断想量表,这样当产生irq中断是就会从thread_vect_table 中开始执行,一般optee中处理frq和在rich os中处理irq中断
LOCAL_FUNC thread_vect_table , :
UNWIND( .fnstart)
UNWIND( .cantunwind)
b . /* Reset */
b thread_und_handler /* Undefined instruction */
b thread_svc_handler /* System call */
b thread_pabort_handler /* Prefetch abort */
b thread_dabort_handler /* Data abort */
b . /* Reserved */
b thread_irq_handler /* IRQ */
b thread_fiq_handler /* FIQ */
UNWIND( .fnend)
END_FUNC thread_vect_table
irq的话这里当然调用thread_irq_handler
LOCAL_FUNC thread_irq_handler , :
UNWIND( .fnstart)
UNWIND( .cantunwind)
#if defined(CFG_ARM_GICV3)
native_intr_handler irq
#else
foreign_intr_handler irq
#endif
UNWIND( .fnend)
END_FUNC thread_irq_handler
我们没有定义CFG_ARM_GICV3,因此这里走foreign_intr_handler
.macro foreign_intr_handler mode:req
* Mark current thread as suspended
*/
mov w0, #THREAD_FLAGS_EXIT_ON_FOREIGN_INTR
mrs x1, spsr_el1
mrs x2, elr_el1
bl thread_state_suspend
mov w4, w0 /* Supply thread index */
orr w1, w1, #THREAD_CLF_IRQ
ldr w0, =TEESMC_OPTEED_RETURN_CALL_DONE
ldr w1, =OPTEE_SMC_RETURN_RPC_FOREIGN_INTR
mov w2, #0
mov w3, #0
/* w4 is already filled in above */
smc #0
b . /* SMC should not return */
.endm
这个函数很长,总的思想是将当前thread suspend,然后通过smc #0 进入到el3,也就是monitor。在monitor中会回调到sm_vect_table
LOCAL_FUNC sm_vect_table , :
UNWIND( .fnstart)
UNWIND( .cantunwind)
b . /* Reset */
b . /* Undefined instruction */
b sm_smc_entry /* Secure monitor call */
b . /* Prefetch abort */
b . /* Data abort */
b . /* Reserved */
b . /* IRQ */
b sm_fiq_entry /* FIQ */
UNWIND( .fnend)
END_FUNC sm_vect_table
调用sm_smc_entry
LOCAL_FUNC sm_smc_entry , :
UNWIND( .fnstart)
UNWIND( .cantunwind)
srsdb sp!, #CPSR_MODE_MON
push {r0-r7}
clrex /* Clear the exclusive monitor */
/* Find out if we're doing an secure or non-secure entry */
read_scr r1
tst r1, #SCR_NS
bne .smc_from_nsec
/*
* As we're coming from secure world (NS bit cleared) the stack
* pointer points to sm_ctx.sec.r0 at this stage. After the
* instruction below the stack pointer points to sm_ctx.
*/
sub sp, sp, #(SM_CTX_SEC + SM_SEC_CTX_R0)
/* Save secure context */
add r0, sp, #SM_CTX_SEC
bl sm_save_modes_regs
/*
* On FIQ exit we're restoring the non-secure context unchanged, on
* all other exits we're shifting r1-r4 from secure context into
* r0-r3 in non-secure context.
*/
add r8, sp, #(SM_CTX_SEC + SM_SEC_CTX_R0)
ldm r8, {r0-r4}
mov_imm r9, TEESMC_OPTEED_RETURN_FIQ_DONE
cmp r0, r9
addne r8, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R0)
stmne r8, {r1-r4}
//恢复不安全的环境,这里就是normal world中kernel的设定
/* Restore non-secure context */
add r0, sp, #SM_CTX_NSEC
bl sm_restore_modes_regs
//返回到non-secure world
.sm_ret_to_nsec:
/*
* Return to non-secure world
*/
add r0, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R8)
ldm r0, {r8-r12}
/* Update SCR */
read_scr r0
orr r0, r0, #(SCR_NS | SCR_FIQ) /* Set NS and FIQ bit in SCR */
write_scr r0
add sp, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R0)
b .sm_exit //这里真正跳到non-secure world执行
//执行完成后跳到secure world继续执行,所以总的来说在secure world中产生fiq后会保存当前参数跳到normal world执行,执行完成后返回secure wordl继续执行。
.smc_from_nsec:
/*
* As we're coming from non-secure world (NS bit set) the stack
* pointer points to sm_ctx.nsec.r0 at this stage. After the
* instruction below the stack pointer points to sm_ctx.
*/
sub sp, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R0)
bic r1, r1, #(SCR_NS | SCR_FIQ) /* Clear NS and FIQ bit in SCR */
write_scr r1
add r0, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R8)
stm r0, {r8-r12}
mov r0, sp
bl sm_from_nsec
cmp r0, #0
beq .sm_ret_to_nsec
/*
* Continue into secure world
*/
add sp, sp, #(SM_CTX_SEC + SM_SEC_CTX_R0)
.sm_exit:
pop {r0-r7}
rfefd sp!
UNWIND( .fnend)
END_FUNC sm_smc_entry
所以结论就是fiq的处理函数是在non-secure中进行的,即使在secure world中收到fiq中断也会先保存secure world的环境后切到non-secure world执行
void thread_init_per_cpu(void)
{
size_t pos = get_core_pos();
struct thread_core_local *l = thread_get_core_local();
init_sec_mon(pos);
set_tmp_stack(l, GET_STACK(stack_tmp[pos]) - STACK_TMP_OFFS);
set_abt_stack(l, GET_STACK(stack_abt[pos]));
thread_init_vbar();
}
在thread_init_per_cpu 中最重要的是调用thread_init_vbar来保存中断向量表
FUNC thread_init_vbar , :
adr x0, thread_vect_table
msr vbar_el1, x0
ret
END_FUNC thread_init_vbar
可以看到在thread_init_vbar 中是将thread_vect_table 保存到vbar_el1 中,这里的thread_vect_table 就是中断想量表,这样当产生irq中断是就会从thread_vect_table 中开始执行,一般optee中处理frq和在rich os中处理irq中断
LOCAL_FUNC thread_vect_table , :
UNWIND( .fnstart)
UNWIND( .cantunwind)
b . /* Reset */
b thread_und_handler /* Undefined instruction */
b thread_svc_handler /* System call */
b thread_pabort_handler /* Prefetch abort */
b thread_dabort_handler /* Data abort */
b . /* Reserved */
b thread_irq_handler /* IRQ */
b thread_fiq_handler /* FIQ */
UNWIND( .fnend)
END_FUNC thread_vect_table
irq的话这里当然调用thread_irq_handler
LOCAL_FUNC thread_irq_handler , :
UNWIND( .fnstart)
UNWIND( .cantunwind)
#if defined(CFG_ARM_GICV3)
native_intr_handler irq
#else
foreign_intr_handler irq
#endif
UNWIND( .fnend)
END_FUNC thread_irq_handler
我们没有定义CFG_ARM_GICV3,因此这里走foreign_intr_handler
.macro foreign_intr_handler mode:req
* Mark current thread as suspended
*/
mov w0, #THREAD_FLAGS_EXIT_ON_FOREIGN_INTR
mrs x1, spsr_el1
mrs x2, elr_el1
bl thread_state_suspend
mov w4, w0 /* Supply thread index */
orr w1, w1, #THREAD_CLF_IRQ
ldr w0, =TEESMC_OPTEED_RETURN_CALL_DONE
ldr w1, =OPTEE_SMC_RETURN_RPC_FOREIGN_INTR
mov w2, #0
mov w3, #0
/* w4 is already filled in above */
smc #0
b . /* SMC should not return */
.endm
这个函数很长,总的思想是将当前thread suspend,然后通过smc #0 进入到el3,也就是monitor。在monitor中会回调到sm_vect_table
LOCAL_FUNC sm_vect_table , :
UNWIND( .fnstart)
UNWIND( .cantunwind)
b . /* Reset */
b . /* Undefined instruction */
b sm_smc_entry /* Secure monitor call */
b . /* Prefetch abort */
b . /* Data abort */
b . /* Reserved */
b . /* IRQ */
b sm_fiq_entry /* FIQ */
UNWIND( .fnend)
END_FUNC sm_vect_table
调用sm_smc_entry
LOCAL_FUNC sm_smc_entry , :
UNWIND( .fnstart)
UNWIND( .cantunwind)
srsdb sp!, #CPSR_MODE_MON
push {r0-r7}
clrex /* Clear the exclusive monitor */
/* Find out if we're doing an secure or non-secure entry */
read_scr r1
tst r1, #SCR_NS
bne .smc_from_nsec
/*
* As we're coming from secure world (NS bit cleared) the stack
* pointer points to sm_ctx.sec.r0 at this stage. After the
* instruction below the stack pointer points to sm_ctx.
*/
sub sp, sp, #(SM_CTX_SEC + SM_SEC_CTX_R0)
/* Save secure context */
add r0, sp, #SM_CTX_SEC
bl sm_save_modes_regs
/*
* On FIQ exit we're restoring the non-secure context unchanged, on
* all other exits we're shifting r1-r4 from secure context into
* r0-r3 in non-secure context.
*/
add r8, sp, #(SM_CTX_SEC + SM_SEC_CTX_R0)
ldm r8, {r0-r4}
mov_imm r9, TEESMC_OPTEED_RETURN_FIQ_DONE
cmp r0, r9
addne r8, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R0)
stmne r8, {r1-r4}
//恢复不安全的环境,这里就是normal world中kernel的设定
/* Restore non-secure context */
add r0, sp, #SM_CTX_NSEC
bl sm_restore_modes_regs
//返回到non-secure world
.sm_ret_to_nsec:
/*
* Return to non-secure world
*/
add r0, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R8)
ldm r0, {r8-r12}
/* Update SCR */
read_scr r0
orr r0, r0, #(SCR_NS | SCR_FIQ) /* Set NS and FIQ bit in SCR */
write_scr r0
add sp, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R0)
b .sm_exit //这里真正跳到non-secure world执行
//执行完成后跳到secure world继续执行,所以总的来说在secure world中产生fiq后会保存当前参数跳到normal world执行,执行完成后返回secure wordl继续执行。
.smc_from_nsec:
/*
* As we're coming from non-secure world (NS bit set) the stack
* pointer points to sm_ctx.nsec.r0 at this stage. After the
* instruction below the stack pointer points to sm_ctx.
*/
sub sp, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R0)
bic r1, r1, #(SCR_NS | SCR_FIQ) /* Clear NS and FIQ bit in SCR */
write_scr r1
add r0, sp, #(SM_CTX_NSEC + SM_NSEC_CTX_R8)
stm r0, {r8-r12}
mov r0, sp
bl sm_from_nsec
cmp r0, #0
beq .sm_ret_to_nsec
/*
* Continue into secure world
*/
add sp, sp, #(SM_CTX_SEC + SM_SEC_CTX_R0)
.sm_exit:
pop {r0-r7}
rfefd sp!
UNWIND( .fnend)
END_FUNC sm_smc_entry
所以结论就是fiq的处理函数是在non-secure中进行的,即使在secure world中收到fiq中断也会先保存secure world的环境后切到non-secure world执行