arm-trusted-firmware 收到psci的smc处理的过程

当kernel psci 通过smc陷到el3时的入口函数如下:
arm-trusted-firmware-master/bl31/aarch64/runtime_exceptions.S
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.
     */
    handle_sync_exception
    check_vector_size sync_exception_aarch64
在handle_sync_exception中判断是smc_handler64还是smc_handler32
.macro    handle_sync_exception
    /* Enable the SError interrupt */
    msr    daifclr, #DAIF_ABT_BIT

    str    x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]

#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

    /* Other kinds of synchronous exceptions are not handled */
    no_ret    report_unhandled_exception
    .endm
我们这里以smc_handler32为例
smc_handler64:
    /*
     * Populate the parameters for the SMC handler.
     * We already have x0-x4 in place. x5 will point to a cookie (not used
     * now). x6 will point to the context structure (SP_EL3) and x7 will
     * contain flags we need to pass to the handler Hence save x5-x7.
     *
     * Note: x4 only needs to be preserved for AArch32 callers but we do it
     *       for AArch64 callers as well for convenience
     */
    stp    x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]
    stp    x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6]

    /* Save rest of the gpregs and sp_el0*/
    save_x18_to_x29_sp_el0

    mov    x5, xzr
    mov    x6, sp

    /* Get the unique owning entity number */
    ubfx    x16, x0, #FUNCID_OEN_SHIFT, #FUNCID_OEN_WIDTH
    ubfx    x15, x0, #FUNCID_TYPE_SHIFT, #FUNCID_TYPE_WIDTH
    orr    x16, x16, x15, lsl #FUNCID_OEN_WIDTH
//通过__RT_SVC_DESCS_START__ + RT_SVC_DESC_HANDLE 找到需要处理的函数
    adr    x11, (__RT_SVC_DESCS_START__ + RT_SVC_DESC_HANDLE)

    /* Load descriptor index from array of indices */
    adr    x14, rt_svc_descs_indices
//将处理的函数指针放到w15中
    ldrb    w15, [x14, x16]

    /*
     * Restore the saved C runtime stack value which will become the new
     * SP_EL0 i.e. EL3 runtime stack. It was saved in the 'cpu_context'
     * structure prior to the last ERET from EL3.
     */
    ldr    x12, [x6, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]

    /*
     * Any index greater than 127 is invalid. Check bit 7 for
     * a valid index
     */
    tbnz    w15, 7, smc_unknown

    /* Switch to SP_EL0 */
    msr    spsel, #0

    /*
     * Get the descriptor using the index
     * x11 = (base + off), x15 = index
     *
     * handler = (base + off) + (index << log2(size))
     */
    lsl    w10, w15, #RT_SVC_SIZE_LOG2
    ldr    x15, [x11, w10, uxtw]

    /*
     * Save the SPSR_EL3, ELR_EL3, & SCR_EL3 in case there is a world
     * switch during SMC handling.
     * TODO: Revisit if all system registers can be saved later.
     */
    mrs    x16, spsr_el3
    mrs    x17, elr_el3
    mrs    x18, scr_el3
    stp    x16, x17, [x6, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
    str    x18, [x6, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]

    /* Copy SCR_EL3.NS bit to the flag to indicate caller's security */
    bfi    x7, x18, #0, #1

    mov    sp, x12

    /*
     * Call the Secure Monitor Call handler and then drop directly into
     * el3_exit() which will program any remaining architectural state
     * prior to issuing the ERET to the desired lower EL.
     */
#if DEBUG
    cbz    x15, rt_svc_fw_critical_error
#endif
// 跳到x15 执行psci的函数
    blr    x15
//返回el1的kernel
    b    el3_exit

通过x15 跳转到的函数是std_svc_smc_handler
/* Register Standard Service Calls as runtime service */
DECLARE_RT_SVC(
        std_svc,

        OEN_STD_START,
        OEN_STD_END,
        SMC_TYPE_FAST,
        std_svc_setup,
        std_svc_smc_handler
);
这里的std_svc_smc_handler 通过DECLARE_RT_SVC 被定义为runtime service
uintptr_t std_svc_smc_handler(uint32_t smc_fid,
                 u_register_t x1,
                 u_register_t x2,
                 u_register_t x3,
                 u_register_t x4,
                 void *cookie,
                 void *handle,
                 u_register_t flags)
{
    /*
     * Dispatch PSCI calls to PSCI SMC handler and return its return
     * value
     */
    if (is_psci_fid(smc_fid)) {
        uint64_t ret;

#if ENABLE_RUNTIME_INSTRUMENTATION

        /*
         * Flush cache line so that even if CPU power down happens
         * the timestamp update is reflected in memory.
         */
        PMF_WRITE_TIMESTAMP(rt_instr_svc,
            RT_INSTR_ENTER_PSCI,
            PMF_CACHE_MAINT,
            get_cpu_data(cpu_data_pmf_ts[CPU_DATA_PMF_TS0_IDX]));
#endif

        ret = psci_smc_handler(smc_fid, x1, x2, x3, x4,
            cookie, handle, flags);

#if ENABLE_RUNTIME_INSTRUMENTATION
        PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
            RT_INSTR_EXIT_PSCI,
            PMF_NO_CACHE_MAINT);
#endif

        SMC_RET1(handle, ret);
    }

    switch (smc_fid) {
    case ARM_STD_SVC_CALL_COUNT:
        /*
         * Return the number of Standard Service Calls. PSCI is the only
         * standard service implemented; so return number of PSCI calls
         */
        SMC_RET1(handle, PSCI_NUM_CALLS);

    case ARM_STD_SVC_UID:
        /* Return UID to the caller */
        SMC_UUID_RET(handle, arm_svc_uid);

    case ARM_STD_SVC_VERSION:
        /* Return the version of current implementation */
        SMC_RET2(handle, STD_SVC_VERSION_MAJOR, STD_SVC_VERSION_MINOR);

    default:
        WARN("Unimplemented Standard Service Call: 0x%x \n", smc_fid);
        SMC_RET1(handle, SMC_UNK);
    }
}
在std_svc_smc_handler 中通过is_psci_fid(smc_fid)判断是不是smc。psci当然是smc ,因此is_psci_fid(smc_fid) 返回true
然后就调用psci_smc_handler
/*******************************************************************************
 * PSCI top level handler for servicing SMCs.
 ******************************************************************************/
u_register_t psci_smc_handler(uint32_t smc_fid,
              u_register_t x1,
              u_register_t x2,
              u_register_t x3,
              u_register_t x4,
              void *cookie,
              void *handle,
              u_register_t flags)
{
    if (is_caller_secure(flags))
        return SMC_UNK;

    /* Check the fid against the capabilities */
    if (!(psci_caps & define_psci_cap(smc_fid)))
        return SMC_UNK;

    if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {
        /* 32-bit PSCI function, clear top parameter bits */

        x1 = (uint32_t)x1;
        x2 = (uint32_t)x2;
        x3 = (uint32_t)x3;

        switch (smc_fid) {
        case PSCI_VERSION:
            return psci_version();

        case PSCI_CPU_OFF:
            return psci_cpu_off();

        case PSCI_CPU_SUSPEND_AARCH32:
            return psci_cpu_suspend(x1, x2, x3);

        case PSCI_CPU_ON_AARCH32:
            return psci_cpu_on(x1, x2, x3);

        case PSCI_AFFINITY_INFO_AARCH32:
            return psci_affinity_info(x1, x2);

        case PSCI_MIG_AARCH32:
            return psci_migrate(x1);

        case PSCI_MIG_INFO_TYPE:
            return psci_migrate_info_type();

        case PSCI_MIG_INFO_UP_CPU_AARCH32:
            return psci_migrate_info_up_cpu();

        case PSCI_NODE_HW_STATE_AARCH32:
            return psci_node_hw_state(x1, x2);

        case PSCI_SYSTEM_SUSPEND_AARCH32:
            return psci_system_suspend(x1, x2);

        case PSCI_SYSTEM_OFF:
            psci_system_off();
            /* We should never return from psci_system_off() */

        case PSCI_SYSTEM_RESET:
            psci_system_reset();
            /* We should never return from psci_system_reset() */

        case PSCI_FEATURES:
            return psci_features(x1);

#if ENABLE_PSCI_STAT
        case PSCI_STAT_RESIDENCY_AARCH32:
            return psci_stat_residency(x1, x2);

        case PSCI_STAT_COUNT_AARCH32:
            return psci_stat_count(x1, x2);
#endif

        default:
            break;
        }
    } else {
        /* 64-bit PSCI function */

        switch (smc_fid) {
        case PSCI_CPU_SUSPEND_AARCH64:
            return psci_cpu_suspend(x1, x2, x3);

        case PSCI_CPU_ON_AARCH64:
            return psci_cpu_on(x1, x2, x3);

        case PSCI_AFFINITY_INFO_AARCH64:
            return psci_affinity_info(x1, x2);

        case PSCI_MIG_AARCH64:
            return psci_migrate(x1);

        case PSCI_MIG_INFO_UP_CPU_AARCH64:
            return psci_migrate_info_up_cpu();

        case PSCI_NODE_HW_STATE_AARCH64:
            return psci_node_hw_state(x1, x2);

        case PSCI_SYSTEM_SUSPEND_AARCH64:
            return psci_system_suspend(x1, x2);

#if ENABLE_PSCI_STAT
        case PSCI_STAT_RESIDENCY_AARCH64:
            return psci_stat_residency(x1, x2);

        case PSCI_STAT_COUNT_AARCH64:
            return psci_stat_count(x1, x2);
#endif

        default:
            break;
        }
    }

    WARN("Unimplemented PSCI Call: 0x%x \n", smc_fid);
    return SMC_UNK;
}
在psci_smc_handler 中就根据smc的id来调用不同的psci的处理函数。
处理完成后回到smc_handler64,最终通过    b    el3_exit,返回到el1的kernel

  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值