16a7e8ebfSLeon Chen /* 2621eaab5SBo-Chen Chen * Copyright (c) 2022-2023, MediaTek Inc. All rights reserved. 36a7e8ebfSLeon Chen * 46a7e8ebfSLeon Chen * SPDX-License-Identifier: BSD-3-Clause 56a7e8ebfSLeon Chen */ 66a7e8ebfSLeon Chen 76a7e8ebfSLeon Chen #include <assert.h> 86a7e8ebfSLeon Chen #include <errno.h> 924476b2eSBo-Chen Chen #if MTK_SIP_KERNEL_BOOT_ENABLE 1024476b2eSBo-Chen Chen #include <cold_boot.h> 1124476b2eSBo-Chen Chen #endif 126a7e8ebfSLeon Chen #include <common/debug.h> 136a7e8ebfSLeon Chen #include <common/runtime_svc.h> 146a7e8ebfSLeon Chen #include <lib/mtk_init/mtk_init.h> 156a7e8ebfSLeon Chen #include <mtk_sip_svc.h> 166a7e8ebfSLeon Chen 176a7e8ebfSLeon Chen #define SMC_HANDLER_DEBUG(...) VERBOSE(__VA_ARGS__) 186a7e8ebfSLeon Chen #define SMC_HANDLER_DEBUG_NOT_IMP_MSG "%s[0x%x] smc handler not implemented\n" 196a7e8ebfSLeon Chen #define SMC_HANDLER_DEBUG_START_MSG "%s[0x%x] smc handler start, smc desc. index:%d\n" 206a7e8ebfSLeon Chen #define SMC_HANDLER_DEBUG_END_MSG "%s[0x%x] smc handler end\n" 216a7e8ebfSLeon Chen 226a7e8ebfSLeon Chen /* 236a7e8ebfSLeon Chen * These macros below are used to identify SIP calls from Kernel, 246a7e8ebfSLeon Chen * Hypervisor, or 2ndBootloader 256a7e8ebfSLeon Chen */ 266a7e8ebfSLeon Chen #define SIP_FID_ORI_MASK (0xc000) 276a7e8ebfSLeon Chen #define SIP_FID_ORI_SHIFT (14) 286a7e8ebfSLeon Chen #define SIP_FID_KERNEL (0x0) 296a7e8ebfSLeon Chen #define SIP_FID_KERNEL_VIA_GZ (0x1) 306a7e8ebfSLeon Chen #define SIP_FID_GZ (0x2) 316a7e8ebfSLeon Chen 326a7e8ebfSLeon Chen #define GET_SMC_ORI(_fid) (((_fid) & SIP_FID_ORI_MASK) >> SIP_FID_ORI_SHIFT) 336a7e8ebfSLeon Chen #define GET_SMC_ORI_NUM(_fid) ((_fid) & ~(SIP_FID_ORI_MASK)) 346a7e8ebfSLeon Chen 356a7e8ebfSLeon Chen #define is_from_nsel2(_ori) (_ori == SIP_FID_GZ) 366a7e8ebfSLeon Chen #define is_from_bl33(_ori) \ 376a7e8ebfSLeon Chen ((_ori != SIP_FID_GZ) && (is_el1_2nd_bootloader() == 1)) 386a7e8ebfSLeon Chen #define is_from_nsel1(_ori) \ 396a7e8ebfSLeon Chen (((_ori == SIP_FID_KERNEL) || \ 406a7e8ebfSLeon Chen (_ori == SIP_FID_KERNEL_VIA_GZ)) && \ 416a7e8ebfSLeon Chen (is_el1_2nd_bootloader() == 0)) 426a7e8ebfSLeon Chen 436a7e8ebfSLeon Chen #define is_smc_forbidden(_ori) (_ori == SIP_FID_KERNEL_VIA_GZ) 446a7e8ebfSLeon Chen 456a7e8ebfSLeon Chen #define MASK_32_BIT (0xffffffffU) 466a7e8ebfSLeon Chen #define SMC_ID_EXPAND_AS_SMC_OPERATION(_smc_id, _smc_num) \ 476a7e8ebfSLeon Chen case _smc_id##_AARCH32: \ 486a7e8ebfSLeon Chen { \ 496a7e8ebfSLeon Chen x1 = x1 & MASK_32_BIT; \ 506a7e8ebfSLeon Chen x2 = x2 & MASK_32_BIT; \ 516a7e8ebfSLeon Chen x3 = x3 & MASK_32_BIT; \ 526a7e8ebfSLeon Chen x4 = x4 & MASK_32_BIT; \ 536a7e8ebfSLeon Chen } \ 54e138400dSBoyan Karatotev /* fallthrough */ \ 556a7e8ebfSLeon Chen case _smc_id##_AARCH64: \ 566a7e8ebfSLeon Chen { \ 576a7e8ebfSLeon Chen if (_smc_id##_descriptor_index < 0) { \ 586a7e8ebfSLeon Chen SMC_HANDLER_DEBUG(SMC_HANDLER_DEBUG_NOT_IMP_MSG, #_smc_id, smc_id); \ 596a7e8ebfSLeon Chen break; \ 606a7e8ebfSLeon Chen } \ 616a7e8ebfSLeon Chen if (_smc_id##_descriptor_index >= smc_id_descriptor_max) { \ 626a7e8ebfSLeon Chen SMC_HANDLER_DEBUG("smc descriptor index[%d] exceed max[%d]\n", \ 636a7e8ebfSLeon Chen _smc_id##_descriptor_index, smc_id_descriptor_max); \ 646a7e8ebfSLeon Chen break; \ 656a7e8ebfSLeon Chen } \ 666a7e8ebfSLeon Chen SMC_HANDLER_DEBUG(SMC_HANDLER_DEBUG_START_MSG, #_smc_id, smc_id, \ 676a7e8ebfSLeon Chen _smc_id##_descriptor_index); \ 686a7e8ebfSLeon Chen ret = smc_handler_pool[_smc_id##_descriptor_index].smc_handler(x1,\ 696a7e8ebfSLeon Chen x2, x3, x4, handle, &smc_ret); \ 706a7e8ebfSLeon Chen SMC_HANDLER_DEBUG(SMC_HANDLER_DEBUG_END_MSG, #_smc_id, smc_id); \ 716a7e8ebfSLeon Chen break; \ 726a7e8ebfSLeon Chen } 736a7e8ebfSLeon Chen 746a7e8ebfSLeon Chen #define SMC_ID_EXPAND_AS_DESCRIPTOR_INDEX(_smc_id, _smc_num) \ 75da04341eSChris Kay short _smc_id##_descriptor_index __section(".mtk_plat_ro") = -1; 766a7e8ebfSLeon Chen 776a7e8ebfSLeon Chen MTK_SIP_SMC_FROM_BL33_TABLE(SMC_ID_EXPAND_AS_DESCRIPTOR_INDEX); 786a7e8ebfSLeon Chen MTK_SIP_SMC_FROM_NS_EL1_TABLE(SMC_ID_EXPAND_AS_DESCRIPTOR_INDEX); 79621eaab5SBo-Chen Chen MTK_SIP_SMC_FROM_S_EL1_TABLE(SMC_ID_EXPAND_AS_DESCRIPTOR_INDEX); 806a7e8ebfSLeon Chen 816a7e8ebfSLeon Chen IMPORT_SYM(uintptr_t, __MTK_SMC_POOL_START__, MTK_SMC_POOL_START); 826a7e8ebfSLeon Chen IMPORT_SYM(uintptr_t, __MTK_SMC_POOL_END_UNALIGNED__, MTK_SMC_POOL_END_UNALIGNED); 836a7e8ebfSLeon Chen 846a7e8ebfSLeon Chen static const struct smc_descriptor *smc_handler_pool; 856a7e8ebfSLeon Chen static short smc_id_descriptor_max; 866a7e8ebfSLeon Chen 876a7e8ebfSLeon Chen #if !MTK_SIP_KERNEL_BOOT_ENABLE 886a7e8ebfSLeon Chen /* 896a7e8ebfSLeon Chen * If there is no SMC request needs to be served in 2nd bootloader, 906a7e8ebfSLeon Chen * disable the service path inherently. 916a7e8ebfSLeon Chen */ 926a7e8ebfSLeon Chen bool is_el1_2nd_bootloader(void) 936a7e8ebfSLeon Chen { 946a7e8ebfSLeon Chen return false; 956a7e8ebfSLeon Chen } 966a7e8ebfSLeon Chen #endif 976a7e8ebfSLeon Chen 986a7e8ebfSLeon Chen static void print_smc_descriptor(const struct smc_descriptor pool[]) 996a7e8ebfSLeon Chen { 1006a7e8ebfSLeon Chen const struct smc_descriptor *p_smc_desc; 1016a7e8ebfSLeon Chen 102*5f2f3848SGavin Liu VERBOSE("print smc descriptor pool\n"); 1036a7e8ebfSLeon Chen for (p_smc_desc = &pool[0]; 1046a7e8ebfSLeon Chen (char *)p_smc_desc < (char *)MTK_SMC_POOL_END_UNALIGNED; 1056a7e8ebfSLeon Chen p_smc_desc++) { 106*5f2f3848SGavin Liu VERBOSE("descriptor name:%s\n", p_smc_desc->smc_name); 107*5f2f3848SGavin Liu VERBOSE("descriptor index:%d\n", *p_smc_desc->smc_descriptor_index); 108*5f2f3848SGavin Liu VERBOSE("smc id 32:0x%x, smc id 64:0x%x\n", 1096a7e8ebfSLeon Chen p_smc_desc->smc_id_aarch32, p_smc_desc->smc_id_aarch64); 1106a7e8ebfSLeon Chen } 1116a7e8ebfSLeon Chen } 1126a7e8ebfSLeon Chen 1136a7e8ebfSLeon Chen static int mtk_smc_handler_init(void) 1146a7e8ebfSLeon Chen { 1156a7e8ebfSLeon Chen const struct smc_descriptor *iter; 1166a7e8ebfSLeon Chen short index_cnt; 1176a7e8ebfSLeon Chen int ret = 0; 1186a7e8ebfSLeon Chen 1196a7e8ebfSLeon Chen smc_handler_pool = (const struct smc_descriptor *)MTK_SMC_POOL_START; 1206a7e8ebfSLeon Chen /* Designate descriptor index point to smc_handler_pool */ 1216a7e8ebfSLeon Chen for (index_cnt = 0, iter = &smc_handler_pool[0]; 1226a7e8ebfSLeon Chen (char *)iter < (char *)MTK_SMC_POOL_END_UNALIGNED; 1236a7e8ebfSLeon Chen iter++, index_cnt++) { 1246a7e8ebfSLeon Chen if (index_cnt < 0) { 1256a7e8ebfSLeon Chen SMC_HANDLER_DEBUG("smc handler pool index overflow!\n"); 1266a7e8ebfSLeon Chen ret = -EPERM; 1276a7e8ebfSLeon Chen assert(0); 1286a7e8ebfSLeon Chen break; 1296a7e8ebfSLeon Chen } 1306a7e8ebfSLeon Chen *(iter->smc_descriptor_index) = index_cnt; 1316a7e8ebfSLeon Chen } 1326a7e8ebfSLeon Chen smc_id_descriptor_max = index_cnt; 1336a7e8ebfSLeon Chen print_smc_descriptor(smc_handler_pool); 1346a7e8ebfSLeon Chen return ret; 1356a7e8ebfSLeon Chen } 1366a7e8ebfSLeon Chen MTK_EARLY_PLAT_INIT(mtk_smc_handler_init); 1376a7e8ebfSLeon Chen 138621eaab5SBo-Chen Chen /* This function handles Mediatek defined SiP Calls from Secure world */ 139621eaab5SBo-Chen Chen static u_register_t mtk_smc_handler_sel1(uint32_t smc_id, 140621eaab5SBo-Chen Chen u_register_t x1, 141621eaab5SBo-Chen Chen u_register_t x2, 142621eaab5SBo-Chen Chen u_register_t x3, 143621eaab5SBo-Chen Chen u_register_t x4, 144621eaab5SBo-Chen Chen void *cookie, 145621eaab5SBo-Chen Chen void *handle, 146621eaab5SBo-Chen Chen u_register_t flags) 147621eaab5SBo-Chen Chen { 148621eaab5SBo-Chen Chen u_register_t ret = MTK_SIP_E_SUCCESS; 149621eaab5SBo-Chen Chen struct smccc_res smc_ret = {0}; 150621eaab5SBo-Chen Chen 151621eaab5SBo-Chen Chen switch (smc_id) { 152621eaab5SBo-Chen Chen MTK_SIP_SMC_FROM_S_EL1_TABLE(SMC_ID_EXPAND_AS_SMC_OPERATION); 153621eaab5SBo-Chen Chen default: 154621eaab5SBo-Chen Chen INFO("SEL1 SMC ID:0x%x not support\n", smc_id); 155621eaab5SBo-Chen Chen ret = SMC_UNK; 156621eaab5SBo-Chen Chen } 157621eaab5SBo-Chen Chen SMC_RET4(handle, ret, smc_ret.a1, smc_ret.a2, smc_ret.a3); 158621eaab5SBo-Chen Chen } 159621eaab5SBo-Chen Chen 1606a7e8ebfSLeon Chen /* This function handles Mediatek defined SiP Calls from Bootloader */ 1616a7e8ebfSLeon Chen static uintptr_t mtk_smc_handler_bl33(uint32_t smc_id, 1626a7e8ebfSLeon Chen u_register_t x1, 1636a7e8ebfSLeon Chen u_register_t x2, 1646a7e8ebfSLeon Chen u_register_t x3, 1656a7e8ebfSLeon Chen u_register_t x4, 1666a7e8ebfSLeon Chen void *cookie, 1676a7e8ebfSLeon Chen void *handle, 1686a7e8ebfSLeon Chen u_register_t flags) 1696a7e8ebfSLeon Chen { 1706a7e8ebfSLeon Chen uintptr_t ret = MTK_SIP_E_SUCCESS; 1716a7e8ebfSLeon Chen struct smccc_res smc_ret = {0}; 1726a7e8ebfSLeon Chen 1736a7e8ebfSLeon Chen switch (smc_id) { 1746a7e8ebfSLeon Chen MTK_SIP_SMC_FROM_BL33_TABLE(SMC_ID_EXPAND_AS_SMC_OPERATION); 1756a7e8ebfSLeon Chen default: 1766a7e8ebfSLeon Chen INFO("BL33 SMC ID:0x%x not supported\n", smc_id); 1776a7e8ebfSLeon Chen ret = SMC_UNK; 1786a7e8ebfSLeon Chen break; 1796a7e8ebfSLeon Chen } 1806a7e8ebfSLeon Chen SMC_RET4(handle, ret, smc_ret.a1, smc_ret.a2, smc_ret.a3); 1816a7e8ebfSLeon Chen } 1826a7e8ebfSLeon Chen 1836a7e8ebfSLeon Chen /* This function handles Mediatek defined SiP Calls from Kernel */ 1846a7e8ebfSLeon Chen static uintptr_t mtk_smc_handler_nsel1(uint32_t smc_id, 1856a7e8ebfSLeon Chen u_register_t x1, 1866a7e8ebfSLeon Chen u_register_t x2, 1876a7e8ebfSLeon Chen u_register_t x3, 1886a7e8ebfSLeon Chen u_register_t x4, 1896a7e8ebfSLeon Chen void *cookie, 1906a7e8ebfSLeon Chen void *handle, 1916a7e8ebfSLeon Chen u_register_t flags) 1926a7e8ebfSLeon Chen { 1936a7e8ebfSLeon Chen uintptr_t ret = MTK_SIP_E_SUCCESS; 1946a7e8ebfSLeon Chen struct smccc_res smc_ret = {0}; 1956a7e8ebfSLeon Chen 1966a7e8ebfSLeon Chen switch (smc_id) { 1976a7e8ebfSLeon Chen MTK_SIP_SMC_FROM_NS_EL1_TABLE(SMC_ID_EXPAND_AS_SMC_OPERATION); 1986a7e8ebfSLeon Chen default: 1996a7e8ebfSLeon Chen INFO("NSEL1 SMC ID:0x%x not supported\n", smc_id); 2006a7e8ebfSLeon Chen ret = SMC_UNK; 2016a7e8ebfSLeon Chen break; 2026a7e8ebfSLeon Chen } 2036a7e8ebfSLeon Chen SMC_RET4(handle, ret, smc_ret.a1, smc_ret.a2, smc_ret.a3); 2046a7e8ebfSLeon Chen } 2056a7e8ebfSLeon Chen 2066a7e8ebfSLeon Chen static uintptr_t mtk_smc_handler(uint32_t smc_id, 2076a7e8ebfSLeon Chen u_register_t x1, 2086a7e8ebfSLeon Chen u_register_t x2, 2096a7e8ebfSLeon Chen u_register_t x3, 2106a7e8ebfSLeon Chen u_register_t x4, 2116a7e8ebfSLeon Chen void *cookie, 2126a7e8ebfSLeon Chen void *handle, 2136a7e8ebfSLeon Chen u_register_t flags) 2146a7e8ebfSLeon Chen { 2156a7e8ebfSLeon Chen uintptr_t ret = SMC_UNK; 2166a7e8ebfSLeon Chen uint32_t ns; 2176a7e8ebfSLeon Chen uint32_t smc_ori; 2186a7e8ebfSLeon Chen uint32_t smc_num; 2196a7e8ebfSLeon Chen 2206a7e8ebfSLeon Chen /* Get SMC Originator bit 14.15 */ 2216a7e8ebfSLeon Chen smc_ori = GET_SMC_ORI(smc_id); 2226a7e8ebfSLeon Chen /* Get SMC Number. Clean bit 14.15 */ 2236a7e8ebfSLeon Chen smc_num = GET_SMC_ORI_NUM(smc_id); 2246a7e8ebfSLeon Chen 2256a7e8ebfSLeon Chen /* Determine which security state this SMC originated from */ 2266a7e8ebfSLeon Chen ns = is_caller_non_secure(flags); 2276a7e8ebfSLeon Chen 2286a7e8ebfSLeon Chen if (ns && is_smc_forbidden(smc_ori)) { 2296a7e8ebfSLeon Chen ERROR("%s: Forbidden SMC call (0x%x)\n", __func__, smc_id); 2306a7e8ebfSLeon Chen SMC_RET1(handle, ret); 2316a7e8ebfSLeon Chen } 2326a7e8ebfSLeon Chen 2336a7e8ebfSLeon Chen if (!ns) { 2346a7e8ebfSLeon Chen /* SiP SMC service secure world's call */ 235621eaab5SBo-Chen Chen return mtk_smc_handler_sel1(smc_num, x1, x2, x3, x4, 236621eaab5SBo-Chen Chen cookie, handle, flags); 2376a7e8ebfSLeon Chen } 2386a7e8ebfSLeon Chen if (is_from_bl33(smc_ori)) { 2396a7e8ebfSLeon Chen /* SiP SMC service secure bootloader's call */ 2406a7e8ebfSLeon Chen return mtk_smc_handler_bl33(smc_num, x1, x2, x3, x4, 2416a7e8ebfSLeon Chen cookie, handle, flags); 2426a7e8ebfSLeon Chen } else if (is_from_nsel1(smc_ori)) { 2436a7e8ebfSLeon Chen /* SiP SMC service kernel's call */ 2446a7e8ebfSLeon Chen return mtk_smc_handler_nsel1(smc_num, x1, x2, x3, x4, 2456a7e8ebfSLeon Chen cookie, handle, flags); 2466a7e8ebfSLeon Chen } 2476a7e8ebfSLeon Chen INFO("SMC ID:0x%x not supported\n", smc_id); 2486a7e8ebfSLeon Chen SMC_RET1(handle, ret); 2496a7e8ebfSLeon Chen } 2506a7e8ebfSLeon Chen 2516a7e8ebfSLeon Chen /* Define a runtime service descriptor for fast SMC calls */ 2526a7e8ebfSLeon Chen DECLARE_RT_SVC( 2536a7e8ebfSLeon Chen mtk_smc_handler, 2546a7e8ebfSLeon Chen OEN_SIP_START, 2556a7e8ebfSLeon Chen OEN_SIP_END, 2566a7e8ebfSLeon Chen SMC_TYPE_FAST, 2576a7e8ebfSLeon Chen NULL, 2586a7e8ebfSLeon Chen mtk_smc_handler 2596a7e8ebfSLeon Chen ); 260