177c27753SZelalem Aweke /* 21975d28bSSona Mathew * Copyright (c) 2021-2025, 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> 20461c0a5dSElizabeth Ho #include <lib/el3_runtime/cpu_data.h> 2177c27753SZelalem Aweke #include <lib/el3_runtime/pubsub.h> 22d048af0dSJavier Almansa Sobrino #include <lib/extensions/mpam.h> 23c73686a1SBoyan Karatotev #include <lib/extensions/pmuv3.h> 24c73686a1SBoyan Karatotev #include <lib/extensions/sys_reg_trace.h> 25f19dc624Sjohpow01 #include <lib/gpt_rme/gpt_rme.h> 2677c27753SZelalem Aweke 2777c27753SZelalem Aweke #include <lib/spinlock.h> 2877c27753SZelalem Aweke #include <lib/utils.h> 2977c27753SZelalem Aweke #include <lib/xlat_tables/xlat_tables_v2.h> 3077c27753SZelalem Aweke #include <plat/common/common_def.h> 3177c27753SZelalem Aweke #include <plat/common/platform.h> 3277c27753SZelalem Aweke #include <platform_def.h> 3377c27753SZelalem Aweke #include <services/rmmd_svc.h> 3477c27753SZelalem Aweke #include <smccc_helpers.h> 35f92eb7e2SArunachalam Ganapathy #include <lib/extensions/sme.h> 36a4cc85c1SSubhasish Ghosh #include <lib/extensions/sve.h> 3779c0c7faSBoyan Karatotev #include <lib/extensions/spe.h> 3879c0c7faSBoyan Karatotev #include <lib/extensions/trbe.h> 3977c27753SZelalem Aweke #include "rmmd_initial_context.h" 4077c27753SZelalem Aweke #include "rmmd_private.h" 4177c27753SZelalem Aweke 4277c27753SZelalem Aweke /******************************************************************************* 438c980a4aSJavier Almansa Sobrino * RMM boot failure flag 448c980a4aSJavier Almansa Sobrino ******************************************************************************/ 458c980a4aSJavier Almansa Sobrino static bool rmm_boot_failed; 468c980a4aSJavier Almansa Sobrino 478c980a4aSJavier Almansa Sobrino /******************************************************************************* 4877c27753SZelalem Aweke * RMM context information. 4977c27753SZelalem Aweke ******************************************************************************/ 5077c27753SZelalem Aweke rmmd_rmm_context_t rmm_context[PLATFORM_CORE_COUNT]; 5177c27753SZelalem Aweke 5277c27753SZelalem Aweke /******************************************************************************* 5377c27753SZelalem Aweke * RMM entry point information. Discovered on the primary core and reused 5477c27753SZelalem Aweke * on secondary cores. 5577c27753SZelalem Aweke ******************************************************************************/ 5677c27753SZelalem Aweke static entry_point_info_t *rmm_ep_info; 5777c27753SZelalem Aweke 5877c27753SZelalem Aweke /******************************************************************************* 5977c27753SZelalem Aweke * Static function declaration. 6077c27753SZelalem Aweke ******************************************************************************/ 6177c27753SZelalem Aweke static int32_t rmm_init(void); 6277c27753SZelalem Aweke 6377c27753SZelalem Aweke /******************************************************************************* 6477c27753SZelalem Aweke * This function takes an RMM context pointer and performs a synchronous entry 6577c27753SZelalem Aweke * into it. 6677c27753SZelalem Aweke ******************************************************************************/ 6777c27753SZelalem Aweke uint64_t rmmd_rmm_sync_entry(rmmd_rmm_context_t *rmm_ctx) 6877c27753SZelalem Aweke { 6977c27753SZelalem Aweke uint64_t rc; 7077c27753SZelalem Aweke 7177c27753SZelalem Aweke assert(rmm_ctx != NULL); 7277c27753SZelalem Aweke 7377c27753SZelalem Aweke cm_set_context(&(rmm_ctx->cpu_ctx), REALM); 7477c27753SZelalem Aweke 7577c27753SZelalem Aweke /* Restore the realm context assigned above */ 7677c27753SZelalem Aweke cm_el2_sysregs_context_restore(REALM); 7777c27753SZelalem Aweke cm_set_next_eret_context(REALM); 7877c27753SZelalem Aweke 7977c27753SZelalem Aweke /* Enter RMM */ 8077c27753SZelalem Aweke rc = rmmd_rmm_enter(&rmm_ctx->c_rt_ctx); 8177c27753SZelalem Aweke 828b95e848SZelalem Aweke /* 83e58daa66SJayanth Dodderi Chidanand * Save realm context. EL2 Non-secure context will be restored 84e58daa66SJayanth Dodderi Chidanand * before exiting Non-secure world, therefore there is no need 85e58daa66SJayanth Dodderi Chidanand * to clear EL2 context registers. 868b95e848SZelalem Aweke */ 8777c27753SZelalem Aweke cm_el2_sysregs_context_save(REALM); 8877c27753SZelalem Aweke 8977c27753SZelalem Aweke return rc; 9077c27753SZelalem Aweke } 9177c27753SZelalem Aweke 9277c27753SZelalem Aweke /******************************************************************************* 9377c27753SZelalem Aweke * This function returns to the place where rmmd_rmm_sync_entry() was 9477c27753SZelalem Aweke * called originally. 9577c27753SZelalem Aweke ******************************************************************************/ 9677c27753SZelalem Aweke __dead2 void rmmd_rmm_sync_exit(uint64_t rc) 9777c27753SZelalem Aweke { 9877c27753SZelalem Aweke rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()]; 9977c27753SZelalem Aweke 10077c27753SZelalem Aweke /* Get context of the RMM in use by this CPU. */ 10177c27753SZelalem Aweke assert(cm_get_context(REALM) == &(ctx->cpu_ctx)); 10277c27753SZelalem Aweke 10377c27753SZelalem Aweke /* 10477c27753SZelalem Aweke * The RMMD must have initiated the original request through a 10577c27753SZelalem Aweke * synchronous entry into RMM. Jump back to the original C runtime 10677c27753SZelalem Aweke * context with the value of rc in x0; 10777c27753SZelalem Aweke */ 10877c27753SZelalem Aweke rmmd_rmm_exit(ctx->c_rt_ctx, rc); 10977c27753SZelalem Aweke 11077c27753SZelalem Aweke panic(); 11177c27753SZelalem Aweke } 11277c27753SZelalem Aweke 11377c27753SZelalem Aweke static void rmm_el2_context_init(el2_sysregs_t *regs) 11477c27753SZelalem Aweke { 115d6af2344SJayanth Dodderi Chidanand write_el2_ctx_common(regs, spsr_el2, REALM_SPSR_EL2); 116d6af2344SJayanth Dodderi Chidanand write_el2_ctx_common(regs, sctlr_el2, SCTLR_EL2_RES1); 11777c27753SZelalem Aweke } 11877c27753SZelalem Aweke 11977c27753SZelalem Aweke /******************************************************************************* 120a4cc85c1SSubhasish Ghosh * Enable architecture extensions on first entry to Realm world. 121a4cc85c1SSubhasish Ghosh ******************************************************************************/ 122461c0a5dSElizabeth Ho 123a4cc85c1SSubhasish Ghosh static void manage_extensions_realm(cpu_context_t *ctx) 124a4cc85c1SSubhasish Ghosh { 125f92eb7e2SArunachalam Ganapathy /* 126c0e16d30SArunachalam Ganapathy * Enable access to TPIDR2_EL0 if SME/SME2 is enabled for Non Secure world. 127f92eb7e2SArunachalam Ganapathy */ 128f92eb7e2SArunachalam Ganapathy if (is_feat_sme_supported()) { 129f92eb7e2SArunachalam Ganapathy sme_enable(ctx); 130f92eb7e2SArunachalam Ganapathy } 13179c0c7faSBoyan Karatotev 13279c0c7faSBoyan Karatotev /* 13379c0c7faSBoyan Karatotev * SPE and TRBE cannot be fully disabled from EL3 registers alone, only 13479c0c7faSBoyan Karatotev * sysreg access can. In case the EL1 controls leave them active on 13579c0c7faSBoyan Karatotev * context switch, we want the owning security state to be NS so Realm 13679c0c7faSBoyan Karatotev * can't be DOSed. 13779c0c7faSBoyan Karatotev */ 13879c0c7faSBoyan Karatotev if (is_feat_spe_supported()) { 13979c0c7faSBoyan Karatotev spe_disable(ctx); 14079c0c7faSBoyan Karatotev } 14179c0c7faSBoyan Karatotev 14279c0c7faSBoyan Karatotev if (is_feat_trbe_supported()) { 14379c0c7faSBoyan Karatotev trbe_disable(ctx); 14479c0c7faSBoyan Karatotev } 145a4cc85c1SSubhasish Ghosh } 146a4cc85c1SSubhasish Ghosh 147461c0a5dSElizabeth Ho static void manage_extensions_realm_per_world(void) 148461c0a5dSElizabeth Ho { 1494087ed6cSJayanth Dodderi Chidanand cm_el3_arch_init_per_world(&per_world_context[CPU_CONTEXT_REALM]); 1504087ed6cSJayanth Dodderi Chidanand 151461c0a5dSElizabeth Ho if (is_feat_sve_supported()) { 152461c0a5dSElizabeth Ho /* 153461c0a5dSElizabeth Ho * Enable SVE and FPU in realm context when it is enabled for NS. 154461c0a5dSElizabeth Ho * Realm manager must ensure that the SVE and FPU register 155461c0a5dSElizabeth Ho * contexts are properly managed. 156461c0a5dSElizabeth Ho */ 157461c0a5dSElizabeth Ho sve_enable_per_world(&per_world_context[CPU_CONTEXT_REALM]); 158461c0a5dSElizabeth Ho } 159461c0a5dSElizabeth Ho 160461c0a5dSElizabeth Ho /* NS can access this but Realm shouldn't */ 161461c0a5dSElizabeth Ho if (is_feat_sys_reg_trace_supported()) { 162461c0a5dSElizabeth Ho sys_reg_trace_disable_per_world(&per_world_context[CPU_CONTEXT_REALM]); 163461c0a5dSElizabeth Ho } 164461c0a5dSElizabeth Ho 165c0e16d30SArunachalam Ganapathy /* 166c0e16d30SArunachalam Ganapathy * If SME/SME2 is supported and enabled for NS world, then disable trapping 167c0e16d30SArunachalam Ganapathy * of SME instructions for Realm world. RMM will save/restore required 168c0e16d30SArunachalam Ganapathy * registers that are shared with SVE/FPU so that Realm can use FPU or SVE. 169c0e16d30SArunachalam Ganapathy */ 170c0e16d30SArunachalam Ganapathy if (is_feat_sme_supported()) { 171c0e16d30SArunachalam Ganapathy sme_enable_per_world(&per_world_context[CPU_CONTEXT_REALM]); 172461c0a5dSElizabeth Ho } 173d048af0dSJavier Almansa Sobrino 174d048af0dSJavier Almansa Sobrino /* 175d048af0dSJavier Almansa Sobrino * If FEAT_MPAM is supported and enabled, then disable trapping access 176d048af0dSJavier Almansa Sobrino * to the MPAM registers for Realm world. Instead, RMM will configure 177d048af0dSJavier Almansa Sobrino * the access to be trapped by itself so it can inject undefined aborts 178d048af0dSJavier Almansa Sobrino * back to the Realm. 179d048af0dSJavier Almansa Sobrino */ 180d048af0dSJavier Almansa Sobrino if (is_feat_mpam_supported()) { 181d048af0dSJavier Almansa Sobrino mpam_enable_per_world(&per_world_context[CPU_CONTEXT_REALM]); 182d048af0dSJavier Almansa Sobrino } 183c0e16d30SArunachalam Ganapathy } 184461c0a5dSElizabeth Ho 185a4cc85c1SSubhasish Ghosh /******************************************************************************* 18677c27753SZelalem Aweke * Jump to the RMM for the first time. 18777c27753SZelalem Aweke ******************************************************************************/ 18877c27753SZelalem Aweke static int32_t rmm_init(void) 18977c27753SZelalem Aweke { 1908c980a4aSJavier Almansa Sobrino long rc; 19177c27753SZelalem Aweke rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()]; 19277c27753SZelalem Aweke 19377c27753SZelalem Aweke INFO("RMM init start.\n"); 19477c27753SZelalem Aweke 195a4cc85c1SSubhasish Ghosh /* Enable architecture extensions */ 196a4cc85c1SSubhasish Ghosh manage_extensions_realm(&ctx->cpu_ctx); 197a4cc85c1SSubhasish Ghosh 198461c0a5dSElizabeth Ho manage_extensions_realm_per_world(); 199461c0a5dSElizabeth Ho 20077c27753SZelalem Aweke /* Initialize RMM EL2 context. */ 20177c27753SZelalem Aweke rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx); 20277c27753SZelalem Aweke 20377c27753SZelalem Aweke rc = rmmd_rmm_sync_entry(ctx); 2048c980a4aSJavier Almansa Sobrino if (rc != E_RMM_BOOT_SUCCESS) { 2058c980a4aSJavier Almansa Sobrino ERROR("RMM init failed: %ld\n", rc); 2068c980a4aSJavier Almansa Sobrino /* Mark the boot as failed for all the CPUs */ 2078c980a4aSJavier Almansa Sobrino rmm_boot_failed = true; 2088c980a4aSJavier Almansa Sobrino return 0; 20977c27753SZelalem Aweke } 21077c27753SZelalem Aweke 21177c27753SZelalem Aweke INFO("RMM init end.\n"); 21277c27753SZelalem Aweke 21377c27753SZelalem Aweke return 1; 21477c27753SZelalem Aweke } 21577c27753SZelalem Aweke 21677c27753SZelalem Aweke /******************************************************************************* 21777c27753SZelalem Aweke * Load and read RMM manifest, setup RMM. 21877c27753SZelalem Aweke ******************************************************************************/ 21977c27753SZelalem Aweke int rmmd_setup(void) 22077c27753SZelalem Aweke { 221dc65ae46SJavier Almansa Sobrino size_t shared_buf_size __unused; 222dc65ae46SJavier Almansa Sobrino uintptr_t shared_buf_base; 22377c27753SZelalem Aweke uint32_t ep_attr; 22477c27753SZelalem Aweke unsigned int linear_id = plat_my_core_pos(); 22577c27753SZelalem Aweke rmmd_rmm_context_t *rmm_ctx = &rmm_context[linear_id]; 226a97bfa5fSAlexeiFedorov struct rmm_manifest *manifest; 2271d0ca40eSJavier Almansa Sobrino int rc; 22877c27753SZelalem Aweke 22977c27753SZelalem Aweke /* Make sure RME is supported. */ 230eacbef4cSVarun Wadekar if (is_feat_rme_present() == 0U) { 231eacbef4cSVarun Wadekar /* Mark the RMM boot as failed for all the CPUs */ 232eacbef4cSVarun Wadekar rmm_boot_failed = true; 233eacbef4cSVarun Wadekar return -ENOTSUP; 234eacbef4cSVarun Wadekar } 23577c27753SZelalem Aweke 23677c27753SZelalem Aweke rmm_ep_info = bl31_plat_get_next_image_ep_info(REALM); 2378cb9c635SVarun Wadekar if ((rmm_ep_info == NULL) || (rmm_ep_info->pc == 0)) { 23877c27753SZelalem Aweke WARN("No RMM image provided by BL2 boot loader, Booting " 23977c27753SZelalem Aweke "device without RMM initialization. SMCs destined for " 24077c27753SZelalem Aweke "RMM will return SMC_UNK\n"); 241eacbef4cSVarun Wadekar 242adcd74caSVarun Wadekar /* Mark the boot as failed for all the CPUs */ 243adcd74caSVarun Wadekar rmm_boot_failed = true; 24477c27753SZelalem Aweke return -ENOENT; 24577c27753SZelalem Aweke } 24677c27753SZelalem Aweke 24777c27753SZelalem Aweke /* Initialise an entrypoint to set up the CPU context */ 24877c27753SZelalem Aweke ep_attr = EP_REALM; 24977c27753SZelalem Aweke if ((read_sctlr_el3() & SCTLR_EE_BIT) != 0U) { 25077c27753SZelalem Aweke ep_attr |= EP_EE_BIG; 25177c27753SZelalem Aweke } 25277c27753SZelalem Aweke 25377c27753SZelalem Aweke SET_PARAM_HEAD(rmm_ep_info, PARAM_EP, VERSION_1, ep_attr); 25477c27753SZelalem Aweke rmm_ep_info->spsr = SPSR_64(MODE_EL2, 25577c27753SZelalem Aweke MODE_SP_ELX, 25677c27753SZelalem Aweke DISABLE_ALL_EXCEPTIONS); 25777c27753SZelalem Aweke 2588c980a4aSJavier Almansa Sobrino shared_buf_size = 2598c980a4aSJavier Almansa Sobrino plat_rmmd_get_el3_rmm_shared_mem(&shared_buf_base); 2608c980a4aSJavier Almansa Sobrino 2618c980a4aSJavier Almansa Sobrino assert((shared_buf_size == SZ_4K) && 2628c980a4aSJavier Almansa Sobrino ((void *)shared_buf_base != NULL)); 2638c980a4aSJavier Almansa Sobrino 26432904472SSoby Mathew /* Zero out and load the boot manifest at the beginning of the share area */ 265a97bfa5fSAlexeiFedorov manifest = (struct rmm_manifest *)shared_buf_base; 26683a4e8e0SHarry Moulton (void)memset((void *)manifest, 0, sizeof(struct rmm_manifest)); 26732904472SSoby Mathew 2681d0ca40eSJavier Almansa Sobrino rc = plat_rmmd_load_manifest(manifest); 2691d0ca40eSJavier Almansa Sobrino if (rc != 0) { 2701d0ca40eSJavier Almansa Sobrino ERROR("Error loading RMM Boot Manifest (%i)\n", rc); 2710c707813SVarun Wadekar /* Mark the boot as failed for all the CPUs */ 2720c707813SVarun Wadekar rmm_boot_failed = true; 2731d0ca40eSJavier Almansa Sobrino return rc; 2741d0ca40eSJavier Almansa Sobrino } 2751d0ca40eSJavier Almansa Sobrino flush_dcache_range((uintptr_t)shared_buf_base, shared_buf_size); 2761d0ca40eSJavier Almansa Sobrino 2778c980a4aSJavier Almansa Sobrino /* 2788c980a4aSJavier Almansa Sobrino * Prepare coldboot arguments for RMM: 2798c980a4aSJavier Almansa Sobrino * arg0: This CPUID (primary processor). 2808c980a4aSJavier Almansa Sobrino * arg1: Version for this Boot Interface. 2818c980a4aSJavier Almansa Sobrino * arg2: PLATFORM_CORE_COUNT. 2828c980a4aSJavier Almansa Sobrino * arg3: Base address for the EL3 <-> RMM shared area. The boot 2838c980a4aSJavier Almansa Sobrino * manifest will be stored at the beginning of this area. 2848c980a4aSJavier Almansa Sobrino */ 2858c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg0 = linear_id; 2868c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg1 = RMM_EL3_INTERFACE_VERSION; 2878c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg2 = PLATFORM_CORE_COUNT; 2888c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg3 = shared_buf_base; 2898c980a4aSJavier Almansa Sobrino 29077c27753SZelalem Aweke /* Initialise RMM context with this entry point information */ 29177c27753SZelalem Aweke cm_setup_context(&rmm_ctx->cpu_ctx, rmm_ep_info); 29277c27753SZelalem Aweke 29377c27753SZelalem Aweke INFO("RMM setup done.\n"); 29477c27753SZelalem Aweke 29577c27753SZelalem Aweke /* Register init function for deferred init. */ 29677c27753SZelalem Aweke bl31_register_rmm_init(&rmm_init); 29777c27753SZelalem Aweke 29877c27753SZelalem Aweke return 0; 29977c27753SZelalem Aweke } 30077c27753SZelalem Aweke 30177c27753SZelalem Aweke /******************************************************************************* 30277c27753SZelalem Aweke * Forward SMC to the other security state 30377c27753SZelalem Aweke ******************************************************************************/ 30411578303SSoby Mathew static uint64_t rmmd_smc_forward(uint32_t src_sec_state, 30511578303SSoby Mathew uint32_t dst_sec_state, uint64_t x0, 30611578303SSoby Mathew uint64_t x1, uint64_t x2, uint64_t x3, 30711578303SSoby Mathew uint64_t x4, void *handle) 30877c27753SZelalem Aweke { 3098e51cccaSAlexeiFedorov cpu_context_t *ctx = cm_get_context(dst_sec_state); 3108e51cccaSAlexeiFedorov 31177c27753SZelalem Aweke /* Save incoming security state */ 31277c27753SZelalem Aweke cm_el2_sysregs_context_save(src_sec_state); 31377c27753SZelalem Aweke 31477c27753SZelalem Aweke /* Restore outgoing security state */ 31577c27753SZelalem Aweke cm_el2_sysregs_context_restore(dst_sec_state); 31677c27753SZelalem Aweke cm_set_next_eret_context(dst_sec_state); 31777c27753SZelalem Aweke 31811578303SSoby Mathew /* 3198e51cccaSAlexeiFedorov * As per SMCCCv1.2, we need to preserve x4 to x7 unless 32011578303SSoby Mathew * being used as return args. Hence we differentiate the 32111578303SSoby Mathew * onward and backward path. Support upto 8 args in the 32211578303SSoby Mathew * onward path and 4 args in return path. 3238e51cccaSAlexeiFedorov * Register x4 will be preserved by RMM in case it is not 3248e51cccaSAlexeiFedorov * used in return path. 32511578303SSoby Mathew */ 32611578303SSoby Mathew if (src_sec_state == NON_SECURE) { 3278e51cccaSAlexeiFedorov SMC_RET8(ctx, x0, x1, x2, x3, x4, 32877c27753SZelalem Aweke SMC_GET_GP(handle, CTX_GPREG_X5), 32977c27753SZelalem Aweke SMC_GET_GP(handle, CTX_GPREG_X6), 33077c27753SZelalem Aweke SMC_GET_GP(handle, CTX_GPREG_X7)); 33111578303SSoby Mathew } 3328e51cccaSAlexeiFedorov 3338e51cccaSAlexeiFedorov SMC_RET5(ctx, x0, x1, x2, x3, x4); 33477c27753SZelalem Aweke } 33577c27753SZelalem Aweke 33677c27753SZelalem Aweke /******************************************************************************* 33777c27753SZelalem Aweke * This function handles all SMCs in the range reserved for RMI. Each call is 33877c27753SZelalem Aweke * either forwarded to the other security state or handled by the RMM dispatcher 33977c27753SZelalem Aweke ******************************************************************************/ 34077c27753SZelalem Aweke uint64_t rmmd_rmi_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, 34177c27753SZelalem Aweke uint64_t x3, uint64_t x4, void *cookie, 34277c27753SZelalem Aweke void *handle, uint64_t flags) 34377c27753SZelalem Aweke { 34477c27753SZelalem Aweke uint32_t src_sec_state; 34577c27753SZelalem Aweke 3468c980a4aSJavier Almansa Sobrino /* If RMM failed to boot, treat any RMI SMC as unknown */ 3478c980a4aSJavier Almansa Sobrino if (rmm_boot_failed) { 3488c980a4aSJavier Almansa Sobrino WARN("RMMD: Failed to boot up RMM. Ignoring RMI call\n"); 3498c980a4aSJavier Almansa Sobrino SMC_RET1(handle, SMC_UNK); 3508c980a4aSJavier Almansa Sobrino } 3518c980a4aSJavier Almansa Sobrino 35277c27753SZelalem Aweke /* Determine which security state this SMC originated from */ 35377c27753SZelalem Aweke src_sec_state = caller_sec_state(flags); 35477c27753SZelalem Aweke 35577c27753SZelalem Aweke /* RMI must not be invoked by the Secure world */ 35677c27753SZelalem Aweke if (src_sec_state == SMC_FROM_SECURE) { 357319fb084SSoby Mathew WARN("RMMD: RMI invoked by secure world.\n"); 35877c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 35977c27753SZelalem Aweke } 36077c27753SZelalem Aweke 36177c27753SZelalem Aweke /* 36277c27753SZelalem Aweke * Forward an RMI call from the Normal world to the Realm world as it 36377c27753SZelalem Aweke * is. 36477c27753SZelalem Aweke */ 36577c27753SZelalem Aweke if (src_sec_state == SMC_FROM_NON_SECURE) { 36667889630SArunachalam Ganapathy /* 36767889630SArunachalam Ganapathy * If SVE hint bit is set in the flags then update the SMC 36867889630SArunachalam Ganapathy * function id and pass it on to the lower EL. 36967889630SArunachalam Ganapathy */ 37067889630SArunachalam Ganapathy if (is_sve_hint_set(flags)) { 37167889630SArunachalam Ganapathy smc_fid |= (FUNCID_SVE_HINT_MASK << 37267889630SArunachalam Ganapathy FUNCID_SVE_HINT_SHIFT); 37367889630SArunachalam Ganapathy } 374319fb084SSoby Mathew VERBOSE("RMMD: RMI call from non-secure world.\n"); 37511578303SSoby Mathew return rmmd_smc_forward(NON_SECURE, REALM, smc_fid, 37677c27753SZelalem Aweke x1, x2, x3, x4, handle); 37777c27753SZelalem Aweke } 37877c27753SZelalem Aweke 379319fb084SSoby Mathew if (src_sec_state != SMC_FROM_REALM) { 380319fb084SSoby Mathew SMC_RET1(handle, SMC_UNK); 381319fb084SSoby Mathew } 38277c27753SZelalem Aweke 38377c27753SZelalem Aweke switch (smc_fid) { 3848e51cccaSAlexeiFedorov case RMM_RMI_REQ_COMPLETE: { 3858e51cccaSAlexeiFedorov uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5); 38677c27753SZelalem Aweke 3878e51cccaSAlexeiFedorov return rmmd_smc_forward(REALM, NON_SECURE, x1, 3888e51cccaSAlexeiFedorov x2, x3, x4, x5, handle); 3898e51cccaSAlexeiFedorov } 39077c27753SZelalem Aweke default: 391319fb084SSoby Mathew WARN("RMMD: Unsupported RMM call 0x%08x\n", smc_fid); 39277c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 39377c27753SZelalem Aweke } 39477c27753SZelalem Aweke } 39577c27753SZelalem Aweke 39677c27753SZelalem Aweke /******************************************************************************* 39777c27753SZelalem Aweke * This cpu has been turned on. Enter RMM to initialise R-EL2. Entry into RMM 39877c27753SZelalem Aweke * is done after initialising minimal architectural state that guarantees safe 39977c27753SZelalem Aweke * execution. 40077c27753SZelalem Aweke ******************************************************************************/ 40177c27753SZelalem Aweke static void *rmmd_cpu_on_finish_handler(const void *arg) 40277c27753SZelalem Aweke { 4038c980a4aSJavier Almansa Sobrino long rc; 40477c27753SZelalem Aweke uint32_t linear_id = plat_my_core_pos(); 40577c27753SZelalem Aweke rmmd_rmm_context_t *ctx = &rmm_context[linear_id]; 40677c27753SZelalem Aweke 4078c980a4aSJavier Almansa Sobrino if (rmm_boot_failed) { 4088c980a4aSJavier Almansa Sobrino /* RMM Boot failed on a previous CPU. Abort. */ 4098c980a4aSJavier Almansa Sobrino ERROR("RMM Failed to initialize. Ignoring for CPU%d\n", 4108c980a4aSJavier Almansa Sobrino linear_id); 4118c980a4aSJavier Almansa Sobrino return NULL; 4128c980a4aSJavier Almansa Sobrino } 4138c980a4aSJavier Almansa Sobrino 4148c980a4aSJavier Almansa Sobrino /* 4158c980a4aSJavier Almansa Sobrino * Prepare warmboot arguments for RMM: 4168c980a4aSJavier Almansa Sobrino * arg0: This CPUID. 4178c980a4aSJavier Almansa Sobrino * arg1 to arg3: Not used. 4188c980a4aSJavier Almansa Sobrino */ 4198c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg0 = linear_id; 4208c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg1 = 0ULL; 4218c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg2 = 0ULL; 4228c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg3 = 0ULL; 42377c27753SZelalem Aweke 42477c27753SZelalem Aweke /* Initialise RMM context with this entry point information */ 42577c27753SZelalem Aweke cm_setup_context(&ctx->cpu_ctx, rmm_ep_info); 42677c27753SZelalem Aweke 427a4cc85c1SSubhasish Ghosh /* Enable architecture extensions */ 428a4cc85c1SSubhasish Ghosh manage_extensions_realm(&ctx->cpu_ctx); 429a4cc85c1SSubhasish Ghosh 43077c27753SZelalem Aweke /* Initialize RMM EL2 context. */ 43177c27753SZelalem Aweke rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx); 43277c27753SZelalem Aweke 43377c27753SZelalem Aweke rc = rmmd_rmm_sync_entry(ctx); 4348c980a4aSJavier Almansa Sobrino 4358c980a4aSJavier Almansa Sobrino if (rc != E_RMM_BOOT_SUCCESS) { 4368c980a4aSJavier Almansa Sobrino ERROR("RMM init failed on CPU%d: %ld\n", linear_id, rc); 4378c980a4aSJavier Almansa Sobrino /* Mark the boot as failed for any other booting CPU */ 4388c980a4aSJavier Almansa Sobrino rmm_boot_failed = true; 43977c27753SZelalem Aweke } 44077c27753SZelalem Aweke 44177c27753SZelalem Aweke return NULL; 44277c27753SZelalem Aweke } 44377c27753SZelalem Aweke 44477c27753SZelalem Aweke /* Subscribe to PSCI CPU on to initialize RMM on secondary */ 44577c27753SZelalem Aweke SUBSCRIBE_TO_EVENT(psci_cpu_on_finish, rmmd_cpu_on_finish_handler); 44677c27753SZelalem Aweke 447319fb084SSoby Mathew /* Convert GPT lib error to RMMD GTS error */ 448319fb084SSoby Mathew static int gpt_to_gts_error(int error, uint32_t smc_fid, uint64_t address) 449319fb084SSoby Mathew { 450319fb084SSoby Mathew int ret; 451319fb084SSoby Mathew 452319fb084SSoby Mathew if (error == 0) { 453dc65ae46SJavier Almansa Sobrino return E_RMM_OK; 454319fb084SSoby Mathew } 455319fb084SSoby Mathew 456319fb084SSoby Mathew if (error == -EINVAL) { 457dc65ae46SJavier Almansa Sobrino ret = E_RMM_BAD_ADDR; 458319fb084SSoby Mathew } else { 459319fb084SSoby Mathew /* This is the only other error code we expect */ 460319fb084SSoby Mathew assert(error == -EPERM); 461dc65ae46SJavier Almansa Sobrino ret = E_RMM_BAD_PAS; 462319fb084SSoby Mathew } 463319fb084SSoby Mathew 464319fb084SSoby Mathew ERROR("RMMD: PAS Transition failed. GPT ret = %d, PA: 0x%"PRIx64 ", FID = 0x%x\n", 465319fb084SSoby Mathew error, address, smc_fid); 466319fb084SSoby Mathew return ret; 467319fb084SSoby Mathew } 468319fb084SSoby Mathew 4696a88ec8bSRaghu Krishnamurthy static int rmm_el3_ifc_get_feat_register(uint64_t feat_reg_idx, 4706a88ec8bSRaghu Krishnamurthy uint64_t *feat_reg) 4716a88ec8bSRaghu Krishnamurthy { 4726a88ec8bSRaghu Krishnamurthy if (feat_reg_idx != RMM_EL3_FEAT_REG_0_IDX) { 4736a88ec8bSRaghu Krishnamurthy ERROR("RMMD: Failed to get feature register %ld\n", feat_reg_idx); 4746a88ec8bSRaghu Krishnamurthy return E_RMM_INVAL; 4756a88ec8bSRaghu Krishnamurthy } 4766a88ec8bSRaghu Krishnamurthy 4776a88ec8bSRaghu Krishnamurthy *feat_reg = 0UL; 4786a88ec8bSRaghu Krishnamurthy #if RMMD_ENABLE_EL3_TOKEN_SIGN 4796a88ec8bSRaghu Krishnamurthy *feat_reg |= RMM_EL3_FEAT_REG_0_EL3_TOKEN_SIGN_MASK; 4806a88ec8bSRaghu Krishnamurthy #endif 4816a88ec8bSRaghu Krishnamurthy return E_RMM_OK; 4826a88ec8bSRaghu Krishnamurthy } 4836a88ec8bSRaghu Krishnamurthy 484f801fdc2STushar Khandelwal /* 485f801fdc2STushar Khandelwal * Update encryption key associated with @mecid. 486f801fdc2STushar Khandelwal */ 487f801fdc2STushar Khandelwal static int rmmd_mecid_key_update(uint64_t mecid) 488f801fdc2STushar Khandelwal { 489f801fdc2STushar Khandelwal uint64_t mecid_width, mecid_width_mask; 490f801fdc2STushar Khandelwal int ret; 491f801fdc2STushar Khandelwal 492f801fdc2STushar Khandelwal /* 493609ada96SJuan Pablo Conde * Check whether FEAT_MEC is supported by the hardware. If not, return 494609ada96SJuan Pablo Conde * unknown SMC. 495609ada96SJuan Pablo Conde */ 496609ada96SJuan Pablo Conde if (is_feat_mec_supported() == false) { 497609ada96SJuan Pablo Conde return E_RMM_UNK; 498609ada96SJuan Pablo Conde } 499609ada96SJuan Pablo Conde 500609ada96SJuan Pablo Conde /* 501f801fdc2STushar Khandelwal * Check whether the mecid parameter is at most MECIDR_EL2.MECIDWidthm1 + 1 502f801fdc2STushar Khandelwal * in length. 503f801fdc2STushar Khandelwal */ 504f801fdc2STushar Khandelwal mecid_width = ((read_mecidr_el2() >> MECIDR_EL2_MECIDWidthm1_SHIFT) & 505f801fdc2STushar Khandelwal MECIDR_EL2_MECIDWidthm1_MASK) + 1; 506f801fdc2STushar Khandelwal mecid_width_mask = ((1 << mecid_width) - 1); 507f801fdc2STushar Khandelwal if ((mecid & ~mecid_width_mask) != 0U) { 508f801fdc2STushar Khandelwal return E_RMM_INVAL; 509f801fdc2STushar Khandelwal } 510f801fdc2STushar Khandelwal 511f801fdc2STushar Khandelwal ret = plat_rmmd_mecid_key_update(mecid); 512f801fdc2STushar Khandelwal 513f801fdc2STushar Khandelwal if (ret != 0) { 514f801fdc2STushar Khandelwal return E_RMM_UNK; 515f801fdc2STushar Khandelwal } 516f801fdc2STushar Khandelwal return E_RMM_OK; 517f801fdc2STushar Khandelwal } 518f801fdc2STushar Khandelwal 51977c27753SZelalem Aweke /******************************************************************************* 520319fb084SSoby Mathew * This function handles RMM-EL3 interface SMCs 52177c27753SZelalem Aweke ******************************************************************************/ 522319fb084SSoby Mathew uint64_t rmmd_rmm_el3_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, 52377c27753SZelalem Aweke uint64_t x3, uint64_t x4, void *cookie, 52477c27753SZelalem Aweke void *handle, uint64_t flags) 52577c27753SZelalem Aweke { 5266a88ec8bSRaghu Krishnamurthy uint64_t remaining_len = 0UL; 52777c27753SZelalem Aweke uint32_t src_sec_state; 5286a00e9b0SRobert Wakim int ret; 52977c27753SZelalem Aweke 5308c980a4aSJavier Almansa Sobrino /* If RMM failed to boot, treat any RMM-EL3 interface SMC as unknown */ 5318c980a4aSJavier Almansa Sobrino if (rmm_boot_failed) { 5328c980a4aSJavier Almansa Sobrino WARN("RMMD: Failed to boot up RMM. Ignoring RMM-EL3 call\n"); 5338c980a4aSJavier Almansa Sobrino SMC_RET1(handle, SMC_UNK); 5348c980a4aSJavier Almansa Sobrino } 5358c980a4aSJavier Almansa Sobrino 53677c27753SZelalem Aweke /* Determine which security state this SMC originated from */ 53777c27753SZelalem Aweke src_sec_state = caller_sec_state(flags); 53877c27753SZelalem Aweke 53977c27753SZelalem Aweke if (src_sec_state != SMC_FROM_REALM) { 540319fb084SSoby Mathew WARN("RMMD: RMM-EL3 call originated from secure or normal world\n"); 54177c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 54277c27753SZelalem Aweke } 54377c27753SZelalem Aweke 54477c27753SZelalem Aweke switch (smc_fid) { 545e50fedbcSJavier Almansa Sobrino case RMM_GTSI_DELEGATE: 5466a00e9b0SRobert Wakim ret = gpt_delegate_pas(x1, PAGE_SIZE_4KB, SMC_FROM_REALM); 547319fb084SSoby Mathew SMC_RET1(handle, gpt_to_gts_error(ret, smc_fid, x1)); 548e50fedbcSJavier Almansa Sobrino case RMM_GTSI_UNDELEGATE: 5496a00e9b0SRobert Wakim ret = gpt_undelegate_pas(x1, PAGE_SIZE_4KB, SMC_FROM_REALM); 550319fb084SSoby Mathew SMC_RET1(handle, gpt_to_gts_error(ret, smc_fid, x1)); 551e50fedbcSJavier Almansa Sobrino case RMM_ATTEST_GET_REALM_KEY: 552a0435105SSoby Mathew ret = rmmd_attest_get_signing_key(x1, &x2, x3); 553a0435105SSoby Mathew SMC_RET2(handle, ret, x2); 5541975d28bSSona Mathew case RMM_ATTEST_GET_PLAT_TOKEN: 5551975d28bSSona Mathew ret = rmmd_attest_get_platform_token(x1, &x2, x3, &remaining_len); 5561975d28bSSona Mathew SMC_RET3(handle, ret, x2, remaining_len); 5576a88ec8bSRaghu Krishnamurthy case RMM_EL3_FEATURES: 5586a88ec8bSRaghu Krishnamurthy ret = rmm_el3_ifc_get_feat_register(x1, &x2); 5596a88ec8bSRaghu Krishnamurthy SMC_RET2(handle, ret, x2); 5606a88ec8bSRaghu Krishnamurthy #if RMMD_ENABLE_EL3_TOKEN_SIGN 5616a88ec8bSRaghu Krishnamurthy case RMM_EL3_TOKEN_SIGN: 5626a88ec8bSRaghu Krishnamurthy return rmmd_el3_token_sign(handle, x1, x2, x3, x4); 5636a88ec8bSRaghu Krishnamurthy #endif 564*2132c707SSona Mathew 565*2132c707SSona Mathew #if RMMD_ENABLE_IDE_KEY_PROG 566*2132c707SSona Mathew case RMM_IDE_KEY_PROG: 567*2132c707SSona Mathew { 568*2132c707SSona Mathew rp_ide_key_info_t ide_key_info; 569*2132c707SSona Mathew 570*2132c707SSona Mathew ide_key_info.keyqw0 = x4; 571*2132c707SSona Mathew ide_key_info.keyqw1 = SMC_GET_GP(handle, CTX_GPREG_X5); 572*2132c707SSona Mathew ide_key_info.keyqw2 = SMC_GET_GP(handle, CTX_GPREG_X6); 573*2132c707SSona Mathew ide_key_info.keyqw3 = SMC_GET_GP(handle, CTX_GPREG_X7); 574*2132c707SSona Mathew ide_key_info.ifvqw0 = SMC_GET_GP(handle, CTX_GPREG_X8); 575*2132c707SSona Mathew ide_key_info.ifvqw1 = SMC_GET_GP(handle, CTX_GPREG_X9); 576*2132c707SSona Mathew uint64_t x10 = SMC_GET_GP(handle, CTX_GPREG_X10); 577*2132c707SSona Mathew uint64_t x11 = SMC_GET_GP(handle, CTX_GPREG_X11); 578*2132c707SSona Mathew 579*2132c707SSona Mathew ret = rmmd_el3_ide_key_program(x1, x2, x3, &ide_key_info, x10, x11); 580*2132c707SSona Mathew SMC_RET1(handle, ret); 581*2132c707SSona Mathew } 582*2132c707SSona Mathew case RMM_IDE_KEY_SET_GO: 583*2132c707SSona Mathew ret = rmmd_el3_ide_key_set_go(x1, x2, x3, x4, SMC_GET_GP(handle, CTX_GPREG_X5)); 584*2132c707SSona Mathew SMC_RET1(handle, ret); 585*2132c707SSona Mathew case RMM_IDE_KEY_SET_STOP: 586*2132c707SSona Mathew ret = rmmd_el3_ide_key_set_stop(x1, x2, x3, x4, SMC_GET_GP(handle, CTX_GPREG_X5)); 587*2132c707SSona Mathew SMC_RET1(handle, ret); 588*2132c707SSona Mathew case RMM_IDE_KM_PULL_RESPONSE: { 589*2132c707SSona Mathew uint64_t req_resp = 0, req_id = 0, cookie_var = 0; 590*2132c707SSona Mathew 591*2132c707SSona Mathew ret = rmmd_el3_ide_km_pull_response(x1, x2, &req_resp, &req_id, &cookie_var); 592*2132c707SSona Mathew SMC_RET4(handle, ret, req_resp, req_id, cookie_var); 593*2132c707SSona Mathew } 594*2132c707SSona Mathew #endif /* RMMD_ENABLE_IDE_KEY_PROG */ 5958c980a4aSJavier Almansa Sobrino case RMM_BOOT_COMPLETE: 5968c980a4aSJavier Almansa Sobrino VERBOSE("RMMD: running rmmd_rmm_sync_exit\n"); 5978c980a4aSJavier Almansa Sobrino rmmd_rmm_sync_exit(x1); 5988c980a4aSJavier Almansa Sobrino 599f801fdc2STushar Khandelwal case RMM_MECID_KEY_UPDATE: 600f801fdc2STushar Khandelwal ret = rmmd_mecid_key_update(x1); 601f801fdc2STushar Khandelwal SMC_RET1(handle, ret); 60277c27753SZelalem Aweke default: 603319fb084SSoby Mathew WARN("RMMD: Unsupported RMM-EL3 call 0x%08x\n", smc_fid); 60477c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 60577c27753SZelalem Aweke } 60677c27753SZelalem Aweke } 607