【ARM64 ATF 系列 1 -- ATF 中断向量表及SMC 处理流程】

文章目录

    • 1.1 ATF 中断向量表
      • 1.1.1 ATF 汇编宏 vector_base
    • 1.2 ATF SMC 中断处理流程

1.1 ATF 中断向量表

ATF 中断向量表的定义位于文件:bl31/aarch64/runtime_exceptions.S

vector_base runtime_exceptions

        /* ---------------------------------------------------------------------
         * Current EL with SP_EL0 : 0x0 - 0x200
         * ---------------------------------------------------------------------
         */
vector_entry sync_exception_sp_el0
#ifdef MONITOR_TRAPS
        stp x29, x30, [sp, #-16]!

        mrs     x30, esr_el3
        ubfx    x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH

        /* Check for BRK */
        cmp     x30, #EC_BRK
        b.eq    brk_handler

        ldp x29, x30, [sp], #16
#endif /* MONITOR_TRAPS */

        /* We don't expect any synchronous exceptions from EL3 */
        b       report_unhandled_exception
end_vector_entry sync_exception_sp_el0

vector_entry irq_sp_el0
        /*
         * EL3 code is non-reentrant. Any asynchronous exception is a serious
         * error. Loop infinitely.
         */
        b       report_unhandled_interrupt
end_vector_entry irq_sp_el0


vector_entry fiq_sp_el0
        b       report_unhandled_interrupt
end_vector_entry fiq_sp_el0
vector_entry serror_sp_el0
        no_ret  plat_handle_el3_ea
end_vector_entry serror_sp_el0

        /* ---------------------------------------------------------------------
         * Current EL with SP_ELx: 0x200 - 0x400
         * ---------------------------------------------------------------------
         */
vector_entry sync_exception_sp_elx
        /*
         * This exception will trigger if anything went wrong during a previous
         * exception entry or exit or while handling an earlier unexpected
         * synchronous exception. There is a high probability that SP_EL3 is
         * corrupted.
         */
        b       report_unhandled_exception
end_vector_entry sync_exception_sp_elx

vector_entry irq_sp_elx
        b       report_unhandled_interrupt
end_vector_entry irq_sp_elx

vector_entry fiq_sp_elx
        b       report_unhandled_interrupt
end_vector_entry fiq_sp_elx

vector_entry serror_sp_elx
#if !RAS_EXTENSION
        check_if_serror_from_EL3
#endif
        no_ret  plat_handle_el3_ea
end_vector_entry serror_sp_elx
        /* ---------------------------------------------------------------------
         * Lower EL using AArch64 : 0x400 - 0x600
         * ---------------------------------------------------------------------
         */
vector_entry sync_exception_aarch64
        /*
         * This exception vector will be the entry point for SMCs and traps
         * that are unhandled at lower ELs most commonly. SP_EL3 should point
         * to a valid cpu context where the general purpose and system register
         * state can be saved.
         */
        apply_at_speculative_wa
        check_and_unmask_ea
        handle_sync_exception
end_vector_entry sync_exception_aarch64

vector_entry irq_aarch64
        apply_at_speculative_wa
        check_and_unmask_ea
        handle_interrupt_exception irq_aarch64
end_vector_entry irq_aarch64

vector_entry fiq_aarch64
        apply_at_speculative_wa
        check_and_unmask_ea
        handle_interrupt_exception fiq_aarch64
end_vector_entry fiq_aarch64

vector_entry serror_aarch64
        apply_at_speculative_wa
#if RAS_EXTENSION
        msr     daifclr, #DAIF_ABT_BIT
        b       enter_lower_el_async_ea
#else
        handle_async_ea
#endif
end_vector_entry serror_aarch64
        /* ---------------------------------------------------------------------
         * Lower EL using AArch32 : 0x600 - 0x800
         * ---------------------------------------------------------------------
         */
vector_entry sync_exception_aarch32
        /*
         * This exception vector will be the entry point for SMCs and traps
         * that are unhandled at lower ELs most commonly. SP_EL3 should point
         * to a valid cpu context where the general purpose and system register
         * state can be saved.
         */
        apply_at_speculative_wa
        check_and_unmask_ea
        handle_sync_exception
end_vector_entry sync_exception_aarch32

vector_entry irq_aarch32
        apply_at_speculative_wa
        check_and_unmask_ea
        handle_interrupt_exception irq_aarch32
end_vector_entry irq_aarch32

vector_entry fiq_aarch32
        apply_at_speculative_wa
        check_and_unmask_ea
        handle_interrupt_exception fiq_aarch32
end_vector_entry fiq_aarch32

vector_entry serror_aarch32
        apply_at_speculative_wa
#if RAS_EXTENSION
        msr     daifclr, #DAIF_ABT_BIT
        b       enter_lower_el_async_ea
#else
        handle_async_ea
#endif
end_vector_entry serror_aarch32

include/arch/aarch64/asm_macros.S 可以看到向量表被放到了 .vectors 段中:

       /*
         * Declare the exception vector table, enforcing it is aligned on a
         * 2KB boundary, as required by the ARMv8 architecture.
         * Use zero bytes as the fill value to be stored in the padding bytes
         * so that it inserts illegal AArch64 instructions. This increases
         * security, robustness and potentially facilitates debugging.
         */
        .macro vector_base  label, section_name=.vectors
        .section \section_name, "ax"
        .align 11, 0
        \label:
        .endm

bl31/aarch64/bl31_entrypoint.S 可以看到 向量表的基地址赋值给了 _exception_vectors

include/arch/aarch64/el3_common_macros.S 中的 el3_entrypoint_common 函数中将向量表的基地址赋值给了

        .macro el3_entrypoint_common                                    \
                _init_sctlr, _warm_boot_mailbox, _secondary_cold_boot,  \
                _init_memory, _init_c_runtime, _exception_vectors,      \
                _pie_fixup_size
		
		......
        /* ---------------------------------------------------------------------
         * Set the exception vectors.
         * ---------------------------------------------------------------------
         */
        cix_postcode_debug_asm _code=0x150
        adr     x0, \_exception_vectors
        msr     vbar_el3, x0
        isb
		......

1.1.1 ATF 汇编宏 vector_base

对于ARMv7 的定义(include/arch/aarch32/asm_macros.S):

        /*
         * Declare the exception vector table, enforcing it is aligned on a
         * 32 byte boundary.
         */
        .macro vector_base  label
        .section .vectors, "ax"
        .align 5
        \label:
        .endm

对于ARMv8 的定义(include/arch/aarch64/asm_macros.S):

        /*
         * Declare the exception vector table, enforcing it is aligned on a
         * 2KB boundary, as required by the ARMv8 architecture.
         * Use zero bytes as the fill value to be stored in the padding bytes
         * so that it inserts illegal AArch64 instructions. This increases
         * security, robustness and potentially facilitates debugging.
         */
        .macro vector_base  label, section_name=.vectors
        .section \section_name, "ax"
        .align 11, 0
        \label:
        .endm

1.2 ATF SMC 中断处理流程

在上面 1.1 节的内容中我们可以看到处理同步异常的汇编宏: handle_sync_exception(分为AArch32 和 AArch64 两种情况,这里值讨论AArch64),由于 SMC 触发的异常属于同步异常,所以执行 SMC 指令后首先会走到 sync_exception_aarch64 处。看下 sync_exception_aarch64 在ATF 中的实现:

vector_entry sync_exception_aarch64
        /*
         * This exception vector will be the entry point for SMCs and traps
         * that are unhandled at lower ELs most commonly. SP_EL3 should point
         * to a valid cpu context where the general purpose and system register
         * state can be saved.
         */
        apply_at_speculative_wa
        check_and_unmask_ea
        handle_sync_exception
end_vector_entry sync_exception_aarch64

可以看到 SMC 异常的处理包含三部分,接下来分别对这三部做介绍。

  • apply_at_speculative_wa
        .macro  apply_at_speculative_wa
#if ERRATA_SPECULATIVE_AT
        /*
         * Explicitly save x30 so as to free up a register and to enable
         * branching and also, save x29 which will be used in the called
         * function
         */
        stp     x29, x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
        bl      save_and_update_ptw_el1_sys_regs
        ldp     x29, x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
#endif
        .endm
  • 首先,编译器会检查是否启用了规避异步异常的修补方案(ERRATA_SPECULATIVE_AT)。如果启用了,就会执行一系列的指令。
    首先使用STP指令将寄存器x29x30的值存储到堆栈中,以便释放这两个寄存器供后续的指令使用。

  • 然后,它调用 save_and_update_ptw_el1_sys_regs函数。这个函数的作用根据函数名,应该是保存并更新EL1系统寄存器的页表遍历(Page Table Walk, PTW)相关的值。这可能是由于部分ARM处理器存在的一些硬件异常,需要通过软件来进行规避。

  • 最后,它使用LDP指令从堆栈中恢复寄存器x29x30的值。

这段代码的主要作用是,在处理异常时,如果启用了异步异常的规避措施,就保存当前的状态,调用特定的函数进行处理,然后恢复之前的状态。

  • check_and_unmask_ea
        /*
         * For SoCs which do not implement RAS, use DSB as a barrier to
         * synchronize pending external aborts.
         */
        dsb     sy

        /* Unmask the SError interrupt */
        msr     daifclr, #DAIF_ABT_BIT

        /* Use ISB for the above unmask operation to take effect immediately */
        isb

        /*
         * Refer Note 1. No need to restore X30 as both handle_sync_exception
         * and handle_interrupt_exception macro which follow this macro modify
         * X30 anyway.
         */
        str     x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
        mov     x30, #1
        str     x30, [sp, #CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3]
        dmb     sy
  • msr daifclr, #DAIF_ABT_BIT 打开Abort中断,Abort中断分为两种类型:Prefetch Abort和Data Abort。对于这两种Abort中断,处理器都会进入异常处理模式,并跳转到预设的异常处理程序进行处理。
    • Prefetch Abort:这种中断是由于指令预取阶段出现的错误触发的,例如尝试执行一个非法地址中的指令或者违反内存保护策略等。
    • Data Abort:这种中断是由于数据访问阶段出现的错误触发的,例如尝试读取或写入一个非法地址或者违反内存保护策略等。
  • isb:Instruction Synchronization Barrier(指令同步屏障)这条指令确保了在它之前的所有指令都完成后,才开始执行它之后的指令。在这里,它确保了打开Abort中断的设置立即生效。。
  • str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] 将寄存器x30的值存储到堆栈的指定位置。这里的位置是基于sp(Stack Pointer,栈指针)寄存器和偏移量CTX_GPREGS_OFFSET + CTX_GPREG_LR计算得到的。
  • mov x30, #1:将1写入到寄存器x30。
  • str x30, [sp, #CTX_EL3STATE_OFFSET +CTX_IS_IN_EL3]:将寄存器x30的值存储到堆栈的指定位置。这里的位置是基于sp寄存器和偏移量CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3计算得到的。这条指令标志着异常处理程序现在正在 EL3 执行级别中运行。
  • dmb sy:Data Memory Barrier(数据内存屏障)。这条指令确保了在它之前的内存访问指令都完成后,才会执行它之后的指令。

这段代码的主要作用是打开Abort 中断,并将一些寄存器值存储到堆栈中以备后续的异常处理程序使用,同时也标志着异常处理程序正在 EL3执行级别中运行。

  • SMC 中断处理(bl31/aarch64/runtime_exceptions.S):
        /* ---------------------------------------------------------------------
         * This macro handles Synchronous exceptions.
         * Only SMC exceptions are supported.
         * ---------------------------------------------------------------------
         */
        .macro  handle_sync_exception
#if ENABLE_RUNTIME_INSTRUMENTATION
        /*
         * Read the timestamp value and store it in per-cpu data. The value
         * will be extracted from per-cpu data by the C level SMC handler and
         * saved to the PMF timestamp region.
         */
        mrs     x30, cntpct_el0
        str     x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
        mrs     x29, tpidr_el3
        str     x30, [x29, #CPU_DATA_PMF_TS0_OFFSET]
        ldr     x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
#endif

        mrs     x30, esr_el3
        ubfx    x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH

        /* Handle SMC exceptions separately from other synchronous exceptions */
        cmp     x30, #EC_AARCH32_SMC
        b.eq    smc_handler32

        cmp     x30, #EC_AARCH64_SMC
        b.eq    smc_handler64

        /* Synchronous exceptions other than the above are assumed to be EA */
        ldr     x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
        b       enter_lower_el_sync_ea
        .endm
  • 这个宏首先检查是否启用了运行时检测(ENABLE_RUNTIME_INSTRUMENTATION),如果启用了,就会读取物理计数器(CNTPCT_EL0)的值,并将其保存在每个CPU的数据中。这个值会被C级别的SMC处理程序提取并保存到PMF时间戳区域。
  • 然后,读取当前异常状态寄存器(ESR_EL3)的值,使用UBFX指令从中提取异常类(EC)字段。
  • 接着,它会检查异常类字段的值,如果值等于EC_AARCH32_SMC(0x13),表示这是一个32位的安全监视器调用(SMC),就跳转到 smc_handler32 标签处处理;如果值等于EC_AARCH64_SMC,表示这是一个64位的SMC,就跳转到 smc_handler64标签处处理。如果异常类字段的值既不是EC_AARCH32_SMC,也不是EC_AARCH64_SMC,则假定这是一个异步异常(EA),并跳转到enter_lower_el_sync_ea 标签处处理。

关于 ESR_EL3 EC 的字段:
【ARM64 ATF 系列 1 -- ATF 中断向量表及SMC 处理流程】_第1张图片

ATF 代码中对于每个异常类型都做了对应的宏定义(include/arch/aarch64/arch.h)

/* Exception Syndrome register bits and bobs */
#define ESR_EC_SHIFT                    U(26)
#define ESR_EC_MASK                     U(0x3f)
#define ESR_EC_LENGTH                   U(6)
#define ESR_ISS_SHIFT                   U(0)
#define ESR_ISS_LENGTH                  U(25)
#define EC_UNKNOWN                      U(0x0)
#define EC_WFE_WFI                      U(0x1)
#define EC_AARCH32_CP15_MRC_MCR         U(0x3)
#define EC_AARCH32_CP15_MRRC_MCRR       U(0x4)
#define EC_AARCH32_CP14_MRC_MCR         U(0x5)
#define EC_AARCH32_CP14_LDC_STC         U(0x6)
#define EC_FP_SIMD                      U(0x7)
#define EC_AARCH32_CP10_MRC             U(0x8)
#define EC_AARCH32_CP14_MRRC_MCRR       U(0xc)
#define EC_ILLEGAL                      U(0xe)
#define EC_AARCH32_SVC                  U(0x11)
#define EC_AARCH32_HVC                  U(0x12)
#define EC_AARCH32_SMC                  U(0x13)
#define EC_AARCH64_SVC                  U(0x15)
#define EC_AARCH64_HVC                  U(0x16)
#define EC_AARCH64_SMC                  U(0x17)
#define EC_AARCH64_SYS                  U(0x18)
#define EC_IABORT_LOWER_EL              U(0x20)
#define EC_IABORT_CUR_EL                U(0x21)
#define EC_PC_ALIGN                     U(0x22)
#define EC_DABORT_LOWER_EL              U(0x24)
#define EC_DABORT_CUR_EL                U(0x25)
#define EC_SP_ALIGN                     U(0x26)
#define EC_AARCH32_FP                   U(0x28)
#define EC_AARCH64_FP                   U(0x2c)
#define EC_SERROR                       U(0x2f)
#define EC_BRK                          U(0x3c)

你可能感兴趣的:(#,ARM,CPU,安全系列介绍,ARM64,atf,ATF,SMC,SMC,中断处理流程)