177c27753SZelalem Aweke /* 22b0bc4e0SJayanth Dodderi Chidanand * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved. 377c27753SZelalem Aweke * 477c27753SZelalem Aweke * SPDX-License-Identifier: BSD-3-Clause 577c27753SZelalem Aweke */ 677c27753SZelalem Aweke 777c27753SZelalem Aweke #include <assert.h> 877c27753SZelalem Aweke #include <errno.h> 92461bd3aSManish Pandey #include <inttypes.h> 102461bd3aSManish Pandey #include <stdint.h> 1177c27753SZelalem Aweke #include <string.h> 1277c27753SZelalem Aweke 1377c27753SZelalem Aweke #include <arch_helpers.h> 1477c27753SZelalem Aweke #include <arch_features.h> 1577c27753SZelalem Aweke #include <bl31/bl31.h> 1677c27753SZelalem Aweke #include <common/debug.h> 1777c27753SZelalem Aweke #include <common/runtime_svc.h> 1877c27753SZelalem Aweke #include <context.h> 1977c27753SZelalem Aweke #include <lib/el3_runtime/context_mgmt.h> 2077c27753SZelalem Aweke #include <lib/el3_runtime/pubsub.h> 21c73686a1SBoyan Karatotev #include <lib/extensions/pmuv3.h> 22c73686a1SBoyan Karatotev #include <lib/extensions/sys_reg_trace.h> 23f19dc624Sjohpow01 #include <lib/gpt_rme/gpt_rme.h> 2477c27753SZelalem Aweke 2577c27753SZelalem Aweke #include <lib/spinlock.h> 2677c27753SZelalem Aweke #include <lib/utils.h> 2777c27753SZelalem Aweke #include <lib/xlat_tables/xlat_tables_v2.h> 2877c27753SZelalem Aweke #include <plat/common/common_def.h> 2977c27753SZelalem Aweke #include <plat/common/platform.h> 3077c27753SZelalem Aweke #include <platform_def.h> 3177c27753SZelalem Aweke #include <services/rmmd_svc.h> 3277c27753SZelalem Aweke #include <smccc_helpers.h> 33f92eb7e2SArunachalam Ganapathy #include <lib/extensions/sme.h> 34a4cc85c1SSubhasish Ghosh #include <lib/extensions/sve.h> 3577c27753SZelalem Aweke #include "rmmd_initial_context.h" 3677c27753SZelalem Aweke #include "rmmd_private.h" 3777c27753SZelalem Aweke 3877c27753SZelalem Aweke /******************************************************************************* 398c980a4aSJavier Almansa Sobrino * RMM boot failure flag 408c980a4aSJavier Almansa Sobrino ******************************************************************************/ 418c980a4aSJavier Almansa Sobrino static bool rmm_boot_failed; 428c980a4aSJavier Almansa Sobrino 438c980a4aSJavier Almansa Sobrino /******************************************************************************* 4477c27753SZelalem Aweke * RMM context information. 4577c27753SZelalem Aweke ******************************************************************************/ 4677c27753SZelalem Aweke rmmd_rmm_context_t rmm_context[PLATFORM_CORE_COUNT]; 4777c27753SZelalem Aweke 4877c27753SZelalem Aweke /******************************************************************************* 4977c27753SZelalem Aweke * RMM entry point information. Discovered on the primary core and reused 5077c27753SZelalem Aweke * on secondary cores. 5177c27753SZelalem Aweke ******************************************************************************/ 5277c27753SZelalem Aweke static entry_point_info_t *rmm_ep_info; 5377c27753SZelalem Aweke 5477c27753SZelalem Aweke /******************************************************************************* 5577c27753SZelalem Aweke * Static function declaration. 5677c27753SZelalem Aweke ******************************************************************************/ 5777c27753SZelalem Aweke static int32_t rmm_init(void); 5877c27753SZelalem Aweke 5977c27753SZelalem Aweke /******************************************************************************* 6077c27753SZelalem Aweke * This function takes an RMM context pointer and performs a synchronous entry 6177c27753SZelalem Aweke * into it. 6277c27753SZelalem Aweke ******************************************************************************/ 6377c27753SZelalem Aweke uint64_t rmmd_rmm_sync_entry(rmmd_rmm_context_t *rmm_ctx) 6477c27753SZelalem Aweke { 6577c27753SZelalem Aweke uint64_t rc; 6677c27753SZelalem Aweke 6777c27753SZelalem Aweke assert(rmm_ctx != NULL); 6877c27753SZelalem Aweke 6977c27753SZelalem Aweke cm_set_context(&(rmm_ctx->cpu_ctx), REALM); 7077c27753SZelalem Aweke 7177c27753SZelalem Aweke /* Restore the realm context assigned above */ 7277c27753SZelalem Aweke cm_el1_sysregs_context_restore(REALM); 7377c27753SZelalem Aweke cm_el2_sysregs_context_restore(REALM); 7477c27753SZelalem Aweke cm_set_next_eret_context(REALM); 7577c27753SZelalem Aweke 7677c27753SZelalem Aweke /* Enter RMM */ 7777c27753SZelalem Aweke rc = rmmd_rmm_enter(&rmm_ctx->c_rt_ctx); 7877c27753SZelalem Aweke 798b95e848SZelalem Aweke /* 808b95e848SZelalem Aweke * Save realm context. EL1 and EL2 Non-secure 818b95e848SZelalem Aweke * contexts will be restored before exiting to 828b95e848SZelalem Aweke * Non-secure world, therefore there is no need 838b95e848SZelalem Aweke * to clear EL1 and EL2 context registers. 848b95e848SZelalem Aweke */ 8577c27753SZelalem Aweke cm_el1_sysregs_context_save(REALM); 8677c27753SZelalem Aweke cm_el2_sysregs_context_save(REALM); 8777c27753SZelalem Aweke 8877c27753SZelalem Aweke return rc; 8977c27753SZelalem Aweke } 9077c27753SZelalem Aweke 9177c27753SZelalem Aweke /******************************************************************************* 9277c27753SZelalem Aweke * This function returns to the place where rmmd_rmm_sync_entry() was 9377c27753SZelalem Aweke * called originally. 9477c27753SZelalem Aweke ******************************************************************************/ 9577c27753SZelalem Aweke __dead2 void rmmd_rmm_sync_exit(uint64_t rc) 9677c27753SZelalem Aweke { 9777c27753SZelalem Aweke rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()]; 9877c27753SZelalem Aweke 9977c27753SZelalem Aweke /* Get context of the RMM in use by this CPU. */ 10077c27753SZelalem Aweke assert(cm_get_context(REALM) == &(ctx->cpu_ctx)); 10177c27753SZelalem Aweke 10277c27753SZelalem Aweke /* 10377c27753SZelalem Aweke * The RMMD must have initiated the original request through a 10477c27753SZelalem Aweke * synchronous entry into RMM. Jump back to the original C runtime 10577c27753SZelalem Aweke * context with the value of rc in x0; 10677c27753SZelalem Aweke */ 10777c27753SZelalem Aweke rmmd_rmm_exit(ctx->c_rt_ctx, rc); 10877c27753SZelalem Aweke 10977c27753SZelalem Aweke panic(); 11077c27753SZelalem Aweke } 11177c27753SZelalem Aweke 11277c27753SZelalem Aweke static void rmm_el2_context_init(el2_sysregs_t *regs) 11377c27753SZelalem Aweke { 11477c27753SZelalem Aweke regs->ctx_regs[CTX_SPSR_EL2 >> 3] = REALM_SPSR_EL2; 11577c27753SZelalem Aweke regs->ctx_regs[CTX_SCTLR_EL2 >> 3] = SCTLR_EL2_RES1; 11677c27753SZelalem Aweke } 11777c27753SZelalem Aweke 11877c27753SZelalem Aweke /******************************************************************************* 119a4cc85c1SSubhasish Ghosh * Enable architecture extensions on first entry to Realm world. 120a4cc85c1SSubhasish Ghosh ******************************************************************************/ 121a4cc85c1SSubhasish Ghosh static void manage_extensions_realm(cpu_context_t *ctx) 122a4cc85c1SSubhasish Ghosh { 1232b0bc4e0SJayanth Dodderi Chidanand if (is_feat_sve_supported()) { 124a4cc85c1SSubhasish Ghosh /* 125a4cc85c1SSubhasish Ghosh * Enable SVE and FPU in realm context when it is enabled for NS. 126a4cc85c1SSubhasish Ghosh * Realm manager must ensure that the SVE and FPU register 127a4cc85c1SSubhasish Ghosh * contexts are properly managed. 128a4cc85c1SSubhasish Ghosh */ 129a4cc85c1SSubhasish Ghosh sve_enable(ctx); 1302b0bc4e0SJayanth Dodderi Chidanand } 131c73686a1SBoyan Karatotev 132ece8f7d7SBoyan Karatotev /* NS can access this but Realm shouldn't */ 133ece8f7d7SBoyan Karatotev if (is_feat_sys_reg_trace_supported()) { 134ece8f7d7SBoyan Karatotev sys_reg_trace_disable(ctx); 135ece8f7d7SBoyan Karatotev } 136ece8f7d7SBoyan Karatotev 137c73686a1SBoyan Karatotev pmuv3_enable(ctx); 138f92eb7e2SArunachalam Ganapathy 139f92eb7e2SArunachalam Ganapathy /* 140f92eb7e2SArunachalam Ganapathy * If SME/SME2 is supported and enabled for NS world, then enables SME 141f92eb7e2SArunachalam Ganapathy * for Realm world. RMM will save/restore required registers that are 142f92eb7e2SArunachalam Ganapathy * shared with SVE/FPU so that Realm can use FPU or SVE. 143f92eb7e2SArunachalam Ganapathy */ 144f92eb7e2SArunachalam Ganapathy if (is_feat_sme_supported()) { 145f92eb7e2SArunachalam Ganapathy /* sme_enable() also enables SME2 if supported by hardware */ 146f92eb7e2SArunachalam Ganapathy sme_enable(ctx); 147f92eb7e2SArunachalam Ganapathy } 148a4cc85c1SSubhasish Ghosh } 149a4cc85c1SSubhasish Ghosh 150a4cc85c1SSubhasish Ghosh /******************************************************************************* 15177c27753SZelalem Aweke * Jump to the RMM for the first time. 15277c27753SZelalem Aweke ******************************************************************************/ 15377c27753SZelalem Aweke static int32_t rmm_init(void) 15477c27753SZelalem Aweke { 1558c980a4aSJavier Almansa Sobrino long rc; 15677c27753SZelalem Aweke rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()]; 15777c27753SZelalem Aweke 15877c27753SZelalem Aweke INFO("RMM init start.\n"); 15977c27753SZelalem Aweke 160a4cc85c1SSubhasish Ghosh /* Enable architecture extensions */ 161a4cc85c1SSubhasish Ghosh manage_extensions_realm(&ctx->cpu_ctx); 162a4cc85c1SSubhasish Ghosh 16377c27753SZelalem Aweke /* Initialize RMM EL2 context. */ 16477c27753SZelalem Aweke rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx); 16577c27753SZelalem Aweke 16677c27753SZelalem Aweke rc = rmmd_rmm_sync_entry(ctx); 1678c980a4aSJavier Almansa Sobrino if (rc != E_RMM_BOOT_SUCCESS) { 1688c980a4aSJavier Almansa Sobrino ERROR("RMM init failed: %ld\n", rc); 1698c980a4aSJavier Almansa Sobrino /* Mark the boot as failed for all the CPUs */ 1708c980a4aSJavier Almansa Sobrino rmm_boot_failed = true; 1718c980a4aSJavier Almansa Sobrino return 0; 17277c27753SZelalem Aweke } 17377c27753SZelalem Aweke 17477c27753SZelalem Aweke INFO("RMM init end.\n"); 17577c27753SZelalem Aweke 17677c27753SZelalem Aweke return 1; 17777c27753SZelalem Aweke } 17877c27753SZelalem Aweke 17977c27753SZelalem Aweke /******************************************************************************* 18077c27753SZelalem Aweke * Load and read RMM manifest, setup RMM. 18177c27753SZelalem Aweke ******************************************************************************/ 18277c27753SZelalem Aweke int rmmd_setup(void) 18377c27753SZelalem Aweke { 184dc65ae46SJavier Almansa Sobrino size_t shared_buf_size __unused; 185dc65ae46SJavier Almansa Sobrino uintptr_t shared_buf_base; 18677c27753SZelalem Aweke uint32_t ep_attr; 18777c27753SZelalem Aweke unsigned int linear_id = plat_my_core_pos(); 18877c27753SZelalem Aweke rmmd_rmm_context_t *rmm_ctx = &rmm_context[linear_id]; 189a97bfa5fSAlexeiFedorov struct rmm_manifest *manifest; 1901d0ca40eSJavier Almansa Sobrino int rc; 19177c27753SZelalem Aweke 19277c27753SZelalem Aweke /* Make sure RME is supported. */ 19377c27753SZelalem Aweke assert(get_armv9_2_feat_rme_support() != 0U); 19477c27753SZelalem Aweke 19577c27753SZelalem Aweke rmm_ep_info = bl31_plat_get_next_image_ep_info(REALM); 19677c27753SZelalem Aweke if (rmm_ep_info == NULL) { 19777c27753SZelalem Aweke WARN("No RMM image provided by BL2 boot loader, Booting " 19877c27753SZelalem Aweke "device without RMM initialization. SMCs destined for " 19977c27753SZelalem Aweke "RMM will return SMC_UNK\n"); 20077c27753SZelalem Aweke return -ENOENT; 20177c27753SZelalem Aweke } 20277c27753SZelalem Aweke 20377c27753SZelalem Aweke /* Under no circumstances will this parameter be 0 */ 20477c27753SZelalem Aweke assert(rmm_ep_info->pc == RMM_BASE); 20577c27753SZelalem Aweke 20677c27753SZelalem Aweke /* Initialise an entrypoint to set up the CPU context */ 20777c27753SZelalem Aweke ep_attr = EP_REALM; 20877c27753SZelalem Aweke if ((read_sctlr_el3() & SCTLR_EE_BIT) != 0U) { 20977c27753SZelalem Aweke ep_attr |= EP_EE_BIG; 21077c27753SZelalem Aweke } 21177c27753SZelalem Aweke 21277c27753SZelalem Aweke SET_PARAM_HEAD(rmm_ep_info, PARAM_EP, VERSION_1, ep_attr); 21377c27753SZelalem Aweke rmm_ep_info->spsr = SPSR_64(MODE_EL2, 21477c27753SZelalem Aweke MODE_SP_ELX, 21577c27753SZelalem Aweke DISABLE_ALL_EXCEPTIONS); 21677c27753SZelalem Aweke 2178c980a4aSJavier Almansa Sobrino shared_buf_size = 2188c980a4aSJavier Almansa Sobrino plat_rmmd_get_el3_rmm_shared_mem(&shared_buf_base); 2198c980a4aSJavier Almansa Sobrino 2208c980a4aSJavier Almansa Sobrino assert((shared_buf_size == SZ_4K) && 2218c980a4aSJavier Almansa Sobrino ((void *)shared_buf_base != NULL)); 2228c980a4aSJavier Almansa Sobrino 2231d0ca40eSJavier Almansa Sobrino /* Load the boot manifest at the beginning of the shared area */ 224a97bfa5fSAlexeiFedorov manifest = (struct rmm_manifest *)shared_buf_base; 2251d0ca40eSJavier Almansa Sobrino rc = plat_rmmd_load_manifest(manifest); 2261d0ca40eSJavier Almansa Sobrino if (rc != 0) { 2271d0ca40eSJavier Almansa Sobrino ERROR("Error loading RMM Boot Manifest (%i)\n", rc); 2281d0ca40eSJavier Almansa Sobrino return rc; 2291d0ca40eSJavier Almansa Sobrino } 2301d0ca40eSJavier Almansa Sobrino flush_dcache_range((uintptr_t)shared_buf_base, shared_buf_size); 2311d0ca40eSJavier Almansa Sobrino 2328c980a4aSJavier Almansa Sobrino /* 2338c980a4aSJavier Almansa Sobrino * Prepare coldboot arguments for RMM: 2348c980a4aSJavier Almansa Sobrino * arg0: This CPUID (primary processor). 2358c980a4aSJavier Almansa Sobrino * arg1: Version for this Boot Interface. 2368c980a4aSJavier Almansa Sobrino * arg2: PLATFORM_CORE_COUNT. 2378c980a4aSJavier Almansa Sobrino * arg3: Base address for the EL3 <-> RMM shared area. The boot 2388c980a4aSJavier Almansa Sobrino * manifest will be stored at the beginning of this area. 2398c980a4aSJavier Almansa Sobrino */ 2408c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg0 = linear_id; 2418c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg1 = RMM_EL3_INTERFACE_VERSION; 2428c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg2 = PLATFORM_CORE_COUNT; 2438c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg3 = shared_buf_base; 2448c980a4aSJavier Almansa Sobrino 24577c27753SZelalem Aweke /* Initialise RMM context with this entry point information */ 24677c27753SZelalem Aweke cm_setup_context(&rmm_ctx->cpu_ctx, rmm_ep_info); 24777c27753SZelalem Aweke 24877c27753SZelalem Aweke INFO("RMM setup done.\n"); 24977c27753SZelalem Aweke 25077c27753SZelalem Aweke /* Register init function for deferred init. */ 25177c27753SZelalem Aweke bl31_register_rmm_init(&rmm_init); 25277c27753SZelalem Aweke 25377c27753SZelalem Aweke return 0; 25477c27753SZelalem Aweke } 25577c27753SZelalem Aweke 25677c27753SZelalem Aweke /******************************************************************************* 25777c27753SZelalem Aweke * Forward SMC to the other security state 25877c27753SZelalem Aweke ******************************************************************************/ 25911578303SSoby Mathew static uint64_t rmmd_smc_forward(uint32_t src_sec_state, 26011578303SSoby Mathew uint32_t dst_sec_state, uint64_t x0, 26111578303SSoby Mathew uint64_t x1, uint64_t x2, uint64_t x3, 26211578303SSoby Mathew uint64_t x4, void *handle) 26377c27753SZelalem Aweke { 2648e51cccaSAlexeiFedorov cpu_context_t *ctx = cm_get_context(dst_sec_state); 2658e51cccaSAlexeiFedorov 26677c27753SZelalem Aweke /* Save incoming security state */ 26777c27753SZelalem Aweke cm_el1_sysregs_context_save(src_sec_state); 26877c27753SZelalem Aweke cm_el2_sysregs_context_save(src_sec_state); 26977c27753SZelalem Aweke 27077c27753SZelalem Aweke /* Restore outgoing security state */ 27177c27753SZelalem Aweke cm_el1_sysregs_context_restore(dst_sec_state); 27277c27753SZelalem Aweke cm_el2_sysregs_context_restore(dst_sec_state); 27377c27753SZelalem Aweke cm_set_next_eret_context(dst_sec_state); 27477c27753SZelalem Aweke 27511578303SSoby Mathew /* 2768e51cccaSAlexeiFedorov * As per SMCCCv1.2, we need to preserve x4 to x7 unless 27711578303SSoby Mathew * being used as return args. Hence we differentiate the 27811578303SSoby Mathew * onward and backward path. Support upto 8 args in the 27911578303SSoby Mathew * onward path and 4 args in return path. 2808e51cccaSAlexeiFedorov * Register x4 will be preserved by RMM in case it is not 2818e51cccaSAlexeiFedorov * used in return path. 28211578303SSoby Mathew */ 28311578303SSoby Mathew if (src_sec_state == NON_SECURE) { 2848e51cccaSAlexeiFedorov SMC_RET8(ctx, x0, x1, x2, x3, x4, 28577c27753SZelalem Aweke SMC_GET_GP(handle, CTX_GPREG_X5), 28677c27753SZelalem Aweke SMC_GET_GP(handle, CTX_GPREG_X6), 28777c27753SZelalem Aweke SMC_GET_GP(handle, CTX_GPREG_X7)); 28811578303SSoby Mathew } 2898e51cccaSAlexeiFedorov 2908e51cccaSAlexeiFedorov SMC_RET5(ctx, x0, x1, x2, x3, x4); 29177c27753SZelalem Aweke } 29277c27753SZelalem Aweke 29377c27753SZelalem Aweke /******************************************************************************* 29477c27753SZelalem Aweke * This function handles all SMCs in the range reserved for RMI. Each call is 29577c27753SZelalem Aweke * either forwarded to the other security state or handled by the RMM dispatcher 29677c27753SZelalem Aweke ******************************************************************************/ 29777c27753SZelalem Aweke uint64_t rmmd_rmi_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, 29877c27753SZelalem Aweke uint64_t x3, uint64_t x4, void *cookie, 29977c27753SZelalem Aweke void *handle, uint64_t flags) 30077c27753SZelalem Aweke { 30177c27753SZelalem Aweke uint32_t src_sec_state; 30277c27753SZelalem Aweke 3038c980a4aSJavier Almansa Sobrino /* If RMM failed to boot, treat any RMI SMC as unknown */ 3048c980a4aSJavier Almansa Sobrino if (rmm_boot_failed) { 3058c980a4aSJavier Almansa Sobrino WARN("RMMD: Failed to boot up RMM. Ignoring RMI call\n"); 3068c980a4aSJavier Almansa Sobrino SMC_RET1(handle, SMC_UNK); 3078c980a4aSJavier Almansa Sobrino } 3088c980a4aSJavier Almansa Sobrino 30977c27753SZelalem Aweke /* Determine which security state this SMC originated from */ 31077c27753SZelalem Aweke src_sec_state = caller_sec_state(flags); 31177c27753SZelalem Aweke 31277c27753SZelalem Aweke /* RMI must not be invoked by the Secure world */ 31377c27753SZelalem Aweke if (src_sec_state == SMC_FROM_SECURE) { 314319fb084SSoby Mathew WARN("RMMD: RMI invoked by secure world.\n"); 31577c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 31677c27753SZelalem Aweke } 31777c27753SZelalem Aweke 31877c27753SZelalem Aweke /* 31977c27753SZelalem Aweke * Forward an RMI call from the Normal world to the Realm world as it 32077c27753SZelalem Aweke * is. 32177c27753SZelalem Aweke */ 32277c27753SZelalem Aweke if (src_sec_state == SMC_FROM_NON_SECURE) { 323*67889630SArunachalam Ganapathy /* 324*67889630SArunachalam Ganapathy * If SVE hint bit is set in the flags then update the SMC 325*67889630SArunachalam Ganapathy * function id and pass it on to the lower EL. 326*67889630SArunachalam Ganapathy */ 327*67889630SArunachalam Ganapathy if (is_sve_hint_set(flags)) { 328*67889630SArunachalam Ganapathy smc_fid |= (FUNCID_SVE_HINT_MASK << 329*67889630SArunachalam Ganapathy FUNCID_SVE_HINT_SHIFT); 330*67889630SArunachalam Ganapathy } 331319fb084SSoby Mathew VERBOSE("RMMD: RMI call from non-secure world.\n"); 33211578303SSoby Mathew return rmmd_smc_forward(NON_SECURE, REALM, smc_fid, 33377c27753SZelalem Aweke x1, x2, x3, x4, handle); 33477c27753SZelalem Aweke } 33577c27753SZelalem Aweke 336319fb084SSoby Mathew if (src_sec_state != SMC_FROM_REALM) { 337319fb084SSoby Mathew SMC_RET1(handle, SMC_UNK); 338319fb084SSoby Mathew } 33977c27753SZelalem Aweke 34077c27753SZelalem Aweke switch (smc_fid) { 3418e51cccaSAlexeiFedorov case RMM_RMI_REQ_COMPLETE: { 3428e51cccaSAlexeiFedorov uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5); 34377c27753SZelalem Aweke 3448e51cccaSAlexeiFedorov return rmmd_smc_forward(REALM, NON_SECURE, x1, 3458e51cccaSAlexeiFedorov x2, x3, x4, x5, handle); 3468e51cccaSAlexeiFedorov } 34777c27753SZelalem Aweke default: 348319fb084SSoby Mathew WARN("RMMD: Unsupported RMM call 0x%08x\n", smc_fid); 34977c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 35077c27753SZelalem Aweke } 35177c27753SZelalem Aweke } 35277c27753SZelalem Aweke 35377c27753SZelalem Aweke /******************************************************************************* 35477c27753SZelalem Aweke * This cpu has been turned on. Enter RMM to initialise R-EL2. Entry into RMM 35577c27753SZelalem Aweke * is done after initialising minimal architectural state that guarantees safe 35677c27753SZelalem Aweke * execution. 35777c27753SZelalem Aweke ******************************************************************************/ 35877c27753SZelalem Aweke static void *rmmd_cpu_on_finish_handler(const void *arg) 35977c27753SZelalem Aweke { 3608c980a4aSJavier Almansa Sobrino long rc; 36177c27753SZelalem Aweke uint32_t linear_id = plat_my_core_pos(); 36277c27753SZelalem Aweke rmmd_rmm_context_t *ctx = &rmm_context[linear_id]; 36377c27753SZelalem Aweke 3648c980a4aSJavier Almansa Sobrino if (rmm_boot_failed) { 3658c980a4aSJavier Almansa Sobrino /* RMM Boot failed on a previous CPU. Abort. */ 3668c980a4aSJavier Almansa Sobrino ERROR("RMM Failed to initialize. Ignoring for CPU%d\n", 3678c980a4aSJavier Almansa Sobrino linear_id); 3688c980a4aSJavier Almansa Sobrino return NULL; 3698c980a4aSJavier Almansa Sobrino } 3708c980a4aSJavier Almansa Sobrino 3718c980a4aSJavier Almansa Sobrino /* 3728c980a4aSJavier Almansa Sobrino * Prepare warmboot arguments for RMM: 3738c980a4aSJavier Almansa Sobrino * arg0: This CPUID. 3748c980a4aSJavier Almansa Sobrino * arg1 to arg3: Not used. 3758c980a4aSJavier Almansa Sobrino */ 3768c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg0 = linear_id; 3778c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg1 = 0ULL; 3788c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg2 = 0ULL; 3798c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg3 = 0ULL; 38077c27753SZelalem Aweke 38177c27753SZelalem Aweke /* Initialise RMM context with this entry point information */ 38277c27753SZelalem Aweke cm_setup_context(&ctx->cpu_ctx, rmm_ep_info); 38377c27753SZelalem Aweke 384a4cc85c1SSubhasish Ghosh /* Enable architecture extensions */ 385a4cc85c1SSubhasish Ghosh manage_extensions_realm(&ctx->cpu_ctx); 386a4cc85c1SSubhasish Ghosh 38777c27753SZelalem Aweke /* Initialize RMM EL2 context. */ 38877c27753SZelalem Aweke rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx); 38977c27753SZelalem Aweke 39077c27753SZelalem Aweke rc = rmmd_rmm_sync_entry(ctx); 3918c980a4aSJavier Almansa Sobrino 3928c980a4aSJavier Almansa Sobrino if (rc != E_RMM_BOOT_SUCCESS) { 3938c980a4aSJavier Almansa Sobrino ERROR("RMM init failed on CPU%d: %ld\n", linear_id, rc); 3948c980a4aSJavier Almansa Sobrino /* Mark the boot as failed for any other booting CPU */ 3958c980a4aSJavier Almansa Sobrino rmm_boot_failed = true; 39677c27753SZelalem Aweke } 39777c27753SZelalem Aweke 39877c27753SZelalem Aweke return NULL; 39977c27753SZelalem Aweke } 40077c27753SZelalem Aweke 40177c27753SZelalem Aweke /* Subscribe to PSCI CPU on to initialize RMM on secondary */ 40277c27753SZelalem Aweke SUBSCRIBE_TO_EVENT(psci_cpu_on_finish, rmmd_cpu_on_finish_handler); 40377c27753SZelalem Aweke 404319fb084SSoby Mathew /* Convert GPT lib error to RMMD GTS error */ 405319fb084SSoby Mathew static int gpt_to_gts_error(int error, uint32_t smc_fid, uint64_t address) 406319fb084SSoby Mathew { 407319fb084SSoby Mathew int ret; 408319fb084SSoby Mathew 409319fb084SSoby Mathew if (error == 0) { 410dc65ae46SJavier Almansa Sobrino return E_RMM_OK; 411319fb084SSoby Mathew } 412319fb084SSoby Mathew 413319fb084SSoby Mathew if (error == -EINVAL) { 414dc65ae46SJavier Almansa Sobrino ret = E_RMM_BAD_ADDR; 415319fb084SSoby Mathew } else { 416319fb084SSoby Mathew /* This is the only other error code we expect */ 417319fb084SSoby Mathew assert(error == -EPERM); 418dc65ae46SJavier Almansa Sobrino ret = E_RMM_BAD_PAS; 419319fb084SSoby Mathew } 420319fb084SSoby Mathew 421319fb084SSoby Mathew ERROR("RMMD: PAS Transition failed. GPT ret = %d, PA: 0x%"PRIx64 ", FID = 0x%x\n", 422319fb084SSoby Mathew error, address, smc_fid); 423319fb084SSoby Mathew return ret; 424319fb084SSoby Mathew } 425319fb084SSoby Mathew 42677c27753SZelalem Aweke /******************************************************************************* 427319fb084SSoby Mathew * This function handles RMM-EL3 interface SMCs 42877c27753SZelalem Aweke ******************************************************************************/ 429319fb084SSoby Mathew uint64_t rmmd_rmm_el3_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, 43077c27753SZelalem Aweke uint64_t x3, uint64_t x4, void *cookie, 43177c27753SZelalem Aweke void *handle, uint64_t flags) 43277c27753SZelalem Aweke { 43377c27753SZelalem Aweke uint32_t src_sec_state; 4346a00e9b0SRobert Wakim int ret; 43577c27753SZelalem Aweke 4368c980a4aSJavier Almansa Sobrino /* If RMM failed to boot, treat any RMM-EL3 interface SMC as unknown */ 4378c980a4aSJavier Almansa Sobrino if (rmm_boot_failed) { 4388c980a4aSJavier Almansa Sobrino WARN("RMMD: Failed to boot up RMM. Ignoring RMM-EL3 call\n"); 4398c980a4aSJavier Almansa Sobrino SMC_RET1(handle, SMC_UNK); 4408c980a4aSJavier Almansa Sobrino } 4418c980a4aSJavier Almansa Sobrino 44277c27753SZelalem Aweke /* Determine which security state this SMC originated from */ 44377c27753SZelalem Aweke src_sec_state = caller_sec_state(flags); 44477c27753SZelalem Aweke 44577c27753SZelalem Aweke if (src_sec_state != SMC_FROM_REALM) { 446319fb084SSoby Mathew WARN("RMMD: RMM-EL3 call originated from secure or normal world\n"); 44777c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 44877c27753SZelalem Aweke } 44977c27753SZelalem Aweke 45077c27753SZelalem Aweke switch (smc_fid) { 451e50fedbcSJavier Almansa Sobrino case RMM_GTSI_DELEGATE: 4526a00e9b0SRobert Wakim ret = gpt_delegate_pas(x1, PAGE_SIZE_4KB, SMC_FROM_REALM); 453319fb084SSoby Mathew SMC_RET1(handle, gpt_to_gts_error(ret, smc_fid, x1)); 454e50fedbcSJavier Almansa Sobrino case RMM_GTSI_UNDELEGATE: 4556a00e9b0SRobert Wakim ret = gpt_undelegate_pas(x1, PAGE_SIZE_4KB, SMC_FROM_REALM); 456319fb084SSoby Mathew SMC_RET1(handle, gpt_to_gts_error(ret, smc_fid, x1)); 457e50fedbcSJavier Almansa Sobrino case RMM_ATTEST_GET_PLAT_TOKEN: 4580f9159b7SSoby Mathew ret = rmmd_attest_get_platform_token(x1, &x2, x3); 4590f9159b7SSoby Mathew SMC_RET2(handle, ret, x2); 460e50fedbcSJavier Almansa Sobrino case RMM_ATTEST_GET_REALM_KEY: 461a0435105SSoby Mathew ret = rmmd_attest_get_signing_key(x1, &x2, x3); 462a0435105SSoby Mathew SMC_RET2(handle, ret, x2); 4638c980a4aSJavier Almansa Sobrino 4648c980a4aSJavier Almansa Sobrino case RMM_BOOT_COMPLETE: 4658c980a4aSJavier Almansa Sobrino VERBOSE("RMMD: running rmmd_rmm_sync_exit\n"); 4668c980a4aSJavier Almansa Sobrino rmmd_rmm_sync_exit(x1); 4678c980a4aSJavier Almansa Sobrino 46877c27753SZelalem Aweke default: 469319fb084SSoby Mathew WARN("RMMD: Unsupported RMM-EL3 call 0x%08x\n", smc_fid); 47077c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 47177c27753SZelalem Aweke } 47277c27753SZelalem Aweke } 473