REE侧、TEE侧以及Monitor模式或EL3都可接收中断信号。
在系统中存在两个VBAR寄存器和一个MVBAR寄存器,REE侧的VBAR寄存器中存放的是Linux内核的异常向量表基地址,OP-TEE中的VBAR寄存器存放的是OP-TEE系统的中断向量表基地址,而Monitor或者EL3的MVBAR存放的是Monitor模式或EL3运行时的中断向量表基地址,即在Monitor或者EL3阶段是可以接收外部中断信号的。
本节将介绍OP-TEE中断的配置和Monitor或EL3阶段中断的配置。
3.1 ARMv7中Monitor模式的异常向量表
ARMv7架构在ARM扩展出了Monitor模式,Monitor模式属于安全世界状态,用于实现ARM核安全世界状态与正常世界状态之间的切换,且该模式具有独立的中断向量表。
使用MVBAR寄存器来保存该运行模式的中断向量表的基地址。在OP-TEE初始化过程中会调用sm_init函数来初始化Monitor模式的配置,并将Monitor模式的中断向量基地址写入到MVBAR寄存器中,该函数内容如下:
FUNC sm_init , :UNWIND( .fnstart)mrs r1, cpsr //设置Monitor模式使用的栈cps #CPSR_MODE_MONsub sp, r0, #(SM_CTX_SIZE - SM_CTX_NSEC)msr cpsr, r1ldr r0, =sm_vect_table //将Monitor模式的异常向量表地址保存到r0寄存器中write_mvbar r0 //将Monitor模式的异常向量表基地址写入MVBAR寄存器中bx lr //返回END_FUNC sm_init
sm_init函数中写入MVBAR寄存器中的值即是Monitor模式下的异常向量表的基地址——sm_vect_table,该向量表的内容如下:
LOCAL_FUNC sm_vect_table , :UNWIND( .fnstart)UNWIND( .cantunwind)b . /* 重启操作 */b . /* 未定义指令操作 */b sm_smc_entry /* smc异常处理函数 */b . /* 执行时的abort操作 */b . /* 数据abort操作 */b . /* 预留 */b . /* IRQ事件 */b sm_fiq_entry /* FIQ中断处理入口函数 */UNWIND( .fnend)END_FUNC sm_vect_table
从上述异常向量表中可知,当在Monitor模式下接收到FIQ中断时,系统将会调用sm_fiq_entry函数对该FIQ中断进行处理。
3.2 ARMv8中EL3阶段的异常向量表
ARMv8使用ATF中的bl31作为EL3阶段的代码,其作用与ARMv7中Monitor模式下运行的代码作用一致。
在ATF的启动过程中,bl31通过调用el3_entrypoint_common函数来进行EL3运行环境的初始化,在初始化过程中会执行EL3阶段异常向量表的初始化,EL3的异常向量表的基地址为runtime_exception_vectors。EL3异常向量表的内容如下:
vector_base runtime_exceptions/*在EL3阶段不接收同步异常,如果产生当作错误处理 */vector_entry sync_exception_sp_el0no_ret report_unhandled_exceptioncheck_vector_size sync_exception_sp_el0vector_entry irq_sp_el0no_ret report_unhandled_interruptcheck_vector_size irq_sp_el0vector_entry fiq_sp_el0no_ret report_unhandled_interruptcheck_vector_size fiq_sp_el0vector_entry serror_sp_el0no_ret report_unhandled_exceptioncheck_vector_size serror_sp_el0vector_entry sync_exception_sp_elxno_ret report_unhandled_exceptioncheck_vector_size sync_exception_sp_elxvector_entry irq_sp_elxno_ret report_unhandled_interruptcheck_vector_size irq_sp_elxvector_entry fiq_sp_elxno_ret report_unhandled_interruptcheck_vector_size fiq_sp_elxvector_entry serror_sp_elxno_ret report_unhandled_exceptioncheck_vector_size serror_sp_elx/* AArch64的同步异常处理,smc异常将进入该向量中进行处理 */vector_entry sync_exception_aarch64handle_sync_exceptioncheck_vector_size sync_exception_aarch64/* AArch64的同步异常处理,IRQ事件将进入该向量中进行处理 */vector_entry irq_aarch64handle_interrupt_exception irq_aarch64check_vector_size irq_aarch64/* AArch64的同步异常处理,FIQ事件将进入该向量中进行处理 */vector_entry fiq_aarch64handle_interrupt_exception fiq_aarch64check_vector_size fiq_aarch64vector_entry serror_aarch64no_ret report_unhandled_exceptioncheck_vector_size serror_aarch64/* AArch32的同步异常处理,smc异常将进入该向量中进行处理 */vector_entry sync_exception_aarch32handle_sync_exceptioncheck_vector_size sync_exception_aarch32/* AArch64的同步异常处理,IRQ事件将进入该向量中进行处理 */vector_entry irq_aarch32handle_interrupt_exception irq_aarch32check_vector_size irq_aarch32/* AArch64的同步异常处理,FIQ事件将进入该向量中进行处理 */vector_entry fiq_aarch32handle_interrupt_exception fiq_aarch32check_vector_size fiq_aarch32vector_entry serror_aarch32no_ret report_unhandled_exceptioncheck_vector_size serror_aarch32
从异常向量表来看,ARMv8架构中不管是AArch32还是AArch64,当在EL3阶段产生了FIQ事件或者IRQ事件后,bl31将会调用handle_interrupt_exception宏来处理,该宏使用的参数就是产生的异常的标签(handler是应该通过smc id)。
3.3 OP-TEE异常向量的配置
在初始化阶段,OP-TEE异常向量的加载和配置会通过执行thread_init_vbar函数来实现,从初始化起始到配置异常向量表的整个调用过程如图12-2所示。
thread_init_vbar函数在AArch32位系统中的定义如下:
FUNC thread_init_vbar , :UNWIND( .fnstart)/* 设置VBAR寄存器的值 */ldr r0, =thread_vect_tablewrite_vbar r0bx lrUNWIND( .fnend)END_FUNC thread_init_vbarKEEP_PAGER thread_init_vbar
thread_init_vbar函数在AArch64位系统中的定义如下:
FUNC thread_init_vbar , :adr x0, thread_vect_table //获取OP-TEE异常向量表的基地址msr vbar_el1, x0 //将OP-TEE的异常向量表的基地址写入到VBAR寄存器中retEND_FUNC thread_init_vbarKEEP_PAGER thread_init_vbar //thread_init_vbar函数保存到__keep_meta_vars_pager段中
OP-TEE的AArch32中断向量表内容如下:
LOCAL_FUNC thread_vect_table , :UNWIND( .fnstart)UNWIND( .cantunwind)b . /* Reset */b thread_und_handler /* 异常指令处理函数 */b thread_svc_handler /* 用于系统调用 */b thread_pabort_handler /* abort异常处理函数 */b thread_dabort_handler /* 数据abort异常处理 */b . /* Reserved */b thread_irq_handler /* IRQ事件处理函数 */b thread_fiq_handler /* FIQ事件处理函数 */UNWIND( .fnend)END_FUNC thread_vect_tableOP-TEE的AArch64中断向量表内容如下:LOCAL_FUNC thread_vect_table , :.align 7sync_el1_sp0:store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3b el1_sync_abortcheck_vector_size sync_el1_sp0.align 7irq_el1_sp0:store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3b elx_irqcheck_vector_size irq_el1_sp0.align 7fiq_el1_sp0:store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3b elx_fiqcheck_vector_size fiq_el1_sp0.align 7SErrorSP0:b SErrorSP0check_vector_size SErrorSP0.align 7SynchronousExceptionSPx:b SynchronousExceptionSPxcheck_vector_size SynchronousExceptionSPx.align 7IrqSPx:b IrqSPxcheck_vector_size IrqSPx.align 7FiqSPx:b FiqSPxcheck_vector_size FiqSPx.align 7SErrorSPx:b SErrorSPxcheck_vector_size SErrorSPx.align 7el0_sync_a64:store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3mrs x2, esr_el1mrs x3, sp_el0lsr x2, x2, #ESR_EC_SHIFTcmp x2, #ESR_EC_AARCH64_SVCb.eq el0_svcb el0_sync_abortcheck_vector_size el0_sync_a64.align 7el0_irq_a64:store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3b elx_irqcheck_vector_size el0_irq_a64.align 7el0_fiq_a64:store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3b elx_fiqcheck_vector_size el0_fiq_a64.align 7SErrorA64:b SErrorA64check_vector_size SErrorA64.align 7el0_sync_a32:store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3mrs x2, esr_el1mrs x3, sp_el0lsr x2, x2, #ESR_EC_SHIFTcmp x2, #ESR_EC_AARCH32_SVCb.eq el0_svcb el0_sync_abortcheck_vector_size el0_sync_a32.align 7el0_irq_a32:store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3b elx_irqcheck_vector_size el0_irq_a32.align 7el0_fiq_a32:store_xregs sp, THREAD_CORE_LOCAL_X0, 0, 3b elx_fiqcheck_vector_size el0_fiq_a32.align 7SErrorA32:b SErrorA32check_vector_size SErrorA32END_FUNC thread_vect_table
当系统处于OP-TEE中时,系统会到VBAR寄存器中获取OP-TEE的异常向量表基地址,然后根据异常类型获取到FIQ或IRQ事件的处理函数,并对不同的事件进行处理。
针对不同的事件会调用线程向量表thread_vector_table变量中对应的处理函数来完成对该异常事件的处理。
(中断号–》中断处理线程,这里其实我们在之前的线程管理那里有提到,在optee种,有很多的线程,不同的线程提供不同的功能,就是中断号对对应的handler)
下面来看看这个tee os中的线程向量表