optee中的fiq的执行

来源:互联网 发布:mysql source 导入文件 编辑:程序博客网 时间:2024/06/03 16:51
在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执行