baron · 3月24日 · 四川

[答疑]-中断流程举例:在REE(SCR.FIQ=1)侧时产生了FIQ,跳转到EL3后做了哪些事情?

快速连接

👉👉👉【精选】ARMv8/ARMv9架构入门到精通-目录 👈👈👈


 title=

中断流程举例的章节中,图中第1步骤中,给REE的SCR.FIQ=1, 在normal EL0/EL1或EL3时来了一个secure group1的中断,该中断将会被标记为FIQ,target到EL3,然后在EL3的软件逻辑,会将CPU切换到TEE进行处理.......
在这里插入图片描述

以上的流程,最近又被小伙伴们问起,那么我们贴下相关文档和代码看下吧。

中断为何被标记FIQ?
看gicv3的官方文档,可知当cpu处于non-secure EL0/1/2时,来了一个secure group1中断,该中断将被标记为FIQ;当cpu处于EL3时,来了一个secure group1中断,也是被标记为FIQ
在这里插入图片描述
那么中断为什么target到EL3?
从armv8的官方文档中的SCR_EL3寄存器中,可以看到,当SCR_EL3.FIQ=1时,来了一个FIQ,该FIQ会直接target到EL3。
在这里插入图片描述
或者去看armv8文档中的rounting表也行,由下图可以看到,当SCR寄存器的EA或IRQ或FIQ等于1时,这个配置下,cpu在EL0/EL1/EL3产生的EA/IRQ/FIQ异常都将直接target到EL3
在这里插入图片描述
那么FIQ target到EL3之后,意味着什么?
意味着CPU将跳转到VBAR_EL3 + offset_fiq, 我们知道向量表有4个FIQ,那么跳转到哪一个呢?如下图所示,标出了cpu在EL3时来的FIQ、cpu在EL0/EL1时来的FIQ跳转的偏移
在这里插入图片描述

硬件介绍完了,开始撸代码

//这一段一段未实现,猜测,cpu在EL3时,PSTATE.F是disabled,中断不会被PE acknowledged,中断pendind状态
[[思考]-ATF中异常向量表为何没有实现“Current Exception level with SP_ELx, x>0.“](https://blog.csdn.net/weixin_...)

    .align    7
fiq_sp_elx:
    bl    report_unhandled_interrupt   
    check_vector_size fiq_sp_elx

这一段,是cpu在EL0/1时,产生的target到EL3的FIQ的向量表偏移

    .align    7
fiq_aarch64:
    handle_interrupt_exception fiq_aarch64
    check_vector_size fiq_aarch64

handle_interrupt_exception的具体实现如下

    .macro    handle_interrupt_exception label
    /* Enable the SError interrupt */
    msr    daifclr, #DAIF_ABT_BIT

    str    x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
    bl    save_gp_registers

    /*
     * Save the EL3 system registers needed to return from
     * this exception.
     */
    mrs    x0, spsr_el3
    mrs    x1, elr_el3
    stp    x0, x1, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]

    /* Switch to the runtime stack i.e. SP_EL0 */
    ldr    x2, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
    mov    x20, sp
    msr    spsel, #0
    mov    sp, x2

    /*
     * Find out whether this is a valid interrupt type. If the
     * interrupt controller reports a spurious interrupt then
     * return to where we came from.
     */
    bl    plat_ic_get_pending_interrupt_type
    cmp    x0, #INTR_TYPE_INVAL
    b.eq    interrupt_exit_\label

    /*
     * Get the registered handler for this interrupt type. A
     * NULL return value could be 'cause of the following
     * conditions:
     *
     * a. An interrupt of a type was routed correctly but a
     *    handler for its type was not registered.
     *
     * b. An interrupt of a type was not routed correctly so
     *    a handler for its type was not registered.
     *
     * c. An interrupt of a type was routed correctly to EL3,
     *    but was deasserted before its pending state could
     *    be read. Another interrupt of a different type pended
     *    at the same time and its type was reported as pending
     *    instead. However, a handler for this type was not
     *    registered.
     *
     * a. and b. can only happen due to a programming error.
     * The occurrence of c. could be beyond the control of
     * Trusted Firmware. It makes sense to return from this
     * exception instead of reporting an error.
     */
    bl    get_interrupt_type_handler
    cbz    x0, interrupt_exit_\label
    mov    x21, x0

    mov    x0, #INTR_ID_UNAVAILABLE

    /* Set the current security state in the 'flags' parameter */
    mrs    x2, scr_el3
    ubfx    x1, x2, #0, #1

    /* Restore the reference to the 'handle' i.e. SP_EL3 */
    mov    x2, x20

    /*  x3 will point to a cookie (not used now) */
    mov    x3, xzr

    /* Call the interrupt type handler */
    blr    x21

interrupt_exit_\label:
    /* Return from exception, possibly in a different security state */
    b    el3_exit

    .endm

剖析下上述代码,在get_interrupt_type_handler,其实是获取SPD(Secure Payload Dispatcher,何为SPD,请点击这里)初始化时注册的中断。
获取到中断handler后,handler地址返回给X0,又拷贝给X21,最后又blr x21,跳转到handler函数

    bl    get_interrupt_type_handler
    cbz    x0, interrupt_exit_\label
    mov    x21, x0

    /* Call the interrupt type handler */
    blr    x21

那么我们在看看handler函数里都干了什么,我的代码环境使用的optee, 我们就看下SPD=opteed的情况,在ATF代码的opteed_main.c中,如下代码所示,其实就是保存下non-secure寄存器,恢复secure寄存器,然后跳转到secure的线程向量表中。
注意这个线程向量表optee_vectors是在optee中软件定义的,然后又将物理地址传到了ATF的全局变量中。

static uint64_t opteed_sel1_interrupt_handler(uint32_t id,
                        uint32_t flags,
                        void *handle,
                        void *cookie)
{
    uint32_t linear_id;
    optee_context_t *optee_ctx;

    /* Check the security state when the exception was generated */
    assert(get_interrupt_src_ss(flags) == NON_SECURE);

    /* Sanity check the pointer to this cpu's context */
    assert(handle == cm_get_context(NON_SECURE));

    /* Save the non-secure context before entering the OPTEE */
    cm_el1_sysregs_context_save(NON_SECURE);

    /* Get a reference to this cpu's OPTEE context */
    linear_id = plat_my_core_pos();
    optee_ctx = &opteed_sp_context[linear_id];
    assert(&optee_ctx->cpu_ctx == cm_get_context(SECURE));

    cm_set_elr_el3(SECURE, (uint64_t)&optee_vectors->fiq_entry);
    cm_el1_sysregs_context_restore(SECURE);
    cm_set_next_eret_context(SECURE);

    /*
     * Tell the OPTEE that it has to handle an FIQ (synchronously).
     * Also the instruction in normal world where the interrupt was
     * generated is passed for debugging purposes. It is safe to
     * retrieve this address from ELR_EL3 as the secure context will
     * not take effect until el3_exit().
     */
    SMC_RET1(&optee_ctx->cpu_ctx, read_elr_el3());
}

至此,你以为讲完了吗,
再补充一点在gicv3文档中1020和1021中断号的描述

在这里插入图片描述
我们应该会用到1020,那么用在哪里的呢?请看上述汇编代码bl plat_ic_get_pending_interrupt_type的具体实现:

uint32_t plat_ic_get_pending_interrupt_type(void)
{
    unsigned int irqnr;

    assert(IS_IN_EL3());
    irqnr = gicv3_get_pending_interrupt_type();

    switch (irqnr) {
    case PENDING_G1S_INTID:
        return INTR_TYPE_S_EL1;
    case PENDING_G1NS_INTID:
        return INTR_TYPE_NS;
    case GIC_SPURIOUS_INTERRUPT:
        return INTR_TYPE_INVAL;
    default:
        return INTR_TYPE_EL3;
    }
}

其实就是在读取pending的中断号,看看有没有1020或1021,从而获得此次的中断是从secure或non-secure过来的,还是在EL3产生的。然后走相应的逻辑。


关注"Arm精选"公众号,备注进ARM交流讨论区。
图片1.png

推荐阅读
关注数
9441
内容数
191
以易懂、渐进、有序的方式,深入探讨ARMv8/ARMv9架构的核心概念。我们将从基础知识开始,逐步深入,覆盖最新的架构,不再纠缠于过时技术。本系列内容包含但不限于ARM基础、SOC芯片基础、Trustzone、gic、异常和中断、AMBA、Cache、MMU等内容,并将持续更新。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息