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> 33*f92eb7e2SArunachalam 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); 138*f92eb7e2SArunachalam Ganapathy 139*f92eb7e2SArunachalam Ganapathy /* 140*f92eb7e2SArunachalam Ganapathy * If SME/SME2 is supported and enabled for NS world, then enables SME 141*f92eb7e2SArunachalam Ganapathy * for Realm world. RMM will save/restore required registers that are 142*f92eb7e2SArunachalam Ganapathy * shared with SVE/FPU so that Realm can use FPU or SVE. 143*f92eb7e2SArunachalam Ganapathy */ 144*f92eb7e2SArunachalam Ganapathy if (is_feat_sme_supported()) { 145*f92eb7e2SArunachalam Ganapathy /* sme_enable() also enables SME2 if supported by hardware */ 146*f92eb7e2SArunachalam Ganapathy sme_enable(ctx); 147*f92eb7e2SArunachalam 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) { 323319fb084SSoby Mathew VERBOSE("RMMD: RMI call from non-secure world.\n"); 32411578303SSoby Mathew return rmmd_smc_forward(NON_SECURE, REALM, smc_fid, 32577c27753SZelalem Aweke x1, x2, x3, x4, handle); 32677c27753SZelalem Aweke } 32777c27753SZelalem Aweke 328319fb084SSoby Mathew if (src_sec_state != SMC_FROM_REALM) { 329319fb084SSoby Mathew SMC_RET1(handle, SMC_UNK); 330319fb084SSoby Mathew } 33177c27753SZelalem Aweke 33277c27753SZelalem Aweke switch (smc_fid) { 3338e51cccaSAlexeiFedorov case RMM_RMI_REQ_COMPLETE: { 3348e51cccaSAlexeiFedorov uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5); 33577c27753SZelalem Aweke 3368e51cccaSAlexeiFedorov return rmmd_smc_forward(REALM, NON_SECURE, x1, 3378e51cccaSAlexeiFedorov x2, x3, x4, x5, handle); 3388e51cccaSAlexeiFedorov } 33977c27753SZelalem Aweke default: 340319fb084SSoby Mathew WARN("RMMD: Unsupported RMM call 0x%08x\n", smc_fid); 34177c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 34277c27753SZelalem Aweke } 34377c27753SZelalem Aweke } 34477c27753SZelalem Aweke 34577c27753SZelalem Aweke /******************************************************************************* 34677c27753SZelalem Aweke * This cpu has been turned on. Enter RMM to initialise R-EL2. Entry into RMM 34777c27753SZelalem Aweke * is done after initialising minimal architectural state that guarantees safe 34877c27753SZelalem Aweke * execution. 34977c27753SZelalem Aweke ******************************************************************************/ 35077c27753SZelalem Aweke static void *rmmd_cpu_on_finish_handler(const void *arg) 35177c27753SZelalem Aweke { 3528c980a4aSJavier Almansa Sobrino long rc; 35377c27753SZelalem Aweke uint32_t linear_id = plat_my_core_pos(); 35477c27753SZelalem Aweke rmmd_rmm_context_t *ctx = &rmm_context[linear_id]; 35577c27753SZelalem Aweke 3568c980a4aSJavier Almansa Sobrino if (rmm_boot_failed) { 3578c980a4aSJavier Almansa Sobrino /* RMM Boot failed on a previous CPU. Abort. */ 3588c980a4aSJavier Almansa Sobrino ERROR("RMM Failed to initialize. Ignoring for CPU%d\n", 3598c980a4aSJavier Almansa Sobrino linear_id); 3608c980a4aSJavier Almansa Sobrino return NULL; 3618c980a4aSJavier Almansa Sobrino } 3628c980a4aSJavier Almansa Sobrino 3638c980a4aSJavier Almansa Sobrino /* 3648c980a4aSJavier Almansa Sobrino * Prepare warmboot arguments for RMM: 3658c980a4aSJavier Almansa Sobrino * arg0: This CPUID. 3668c980a4aSJavier Almansa Sobrino * arg1 to arg3: Not used. 3678c980a4aSJavier Almansa Sobrino */ 3688c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg0 = linear_id; 3698c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg1 = 0ULL; 3708c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg2 = 0ULL; 3718c980a4aSJavier Almansa Sobrino rmm_ep_info->args.arg3 = 0ULL; 37277c27753SZelalem Aweke 37377c27753SZelalem Aweke /* Initialise RMM context with this entry point information */ 37477c27753SZelalem Aweke cm_setup_context(&ctx->cpu_ctx, rmm_ep_info); 37577c27753SZelalem Aweke 376a4cc85c1SSubhasish Ghosh /* Enable architecture extensions */ 377a4cc85c1SSubhasish Ghosh manage_extensions_realm(&ctx->cpu_ctx); 378a4cc85c1SSubhasish Ghosh 37977c27753SZelalem Aweke /* Initialize RMM EL2 context. */ 38077c27753SZelalem Aweke rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx); 38177c27753SZelalem Aweke 38277c27753SZelalem Aweke rc = rmmd_rmm_sync_entry(ctx); 3838c980a4aSJavier Almansa Sobrino 3848c980a4aSJavier Almansa Sobrino if (rc != E_RMM_BOOT_SUCCESS) { 3858c980a4aSJavier Almansa Sobrino ERROR("RMM init failed on CPU%d: %ld\n", linear_id, rc); 3868c980a4aSJavier Almansa Sobrino /* Mark the boot as failed for any other booting CPU */ 3878c980a4aSJavier Almansa Sobrino rmm_boot_failed = true; 38877c27753SZelalem Aweke } 38977c27753SZelalem Aweke 39077c27753SZelalem Aweke return NULL; 39177c27753SZelalem Aweke } 39277c27753SZelalem Aweke 39377c27753SZelalem Aweke /* Subscribe to PSCI CPU on to initialize RMM on secondary */ 39477c27753SZelalem Aweke SUBSCRIBE_TO_EVENT(psci_cpu_on_finish, rmmd_cpu_on_finish_handler); 39577c27753SZelalem Aweke 396319fb084SSoby Mathew /* Convert GPT lib error to RMMD GTS error */ 397319fb084SSoby Mathew static int gpt_to_gts_error(int error, uint32_t smc_fid, uint64_t address) 398319fb084SSoby Mathew { 399319fb084SSoby Mathew int ret; 400319fb084SSoby Mathew 401319fb084SSoby Mathew if (error == 0) { 402dc65ae46SJavier Almansa Sobrino return E_RMM_OK; 403319fb084SSoby Mathew } 404319fb084SSoby Mathew 405319fb084SSoby Mathew if (error == -EINVAL) { 406dc65ae46SJavier Almansa Sobrino ret = E_RMM_BAD_ADDR; 407319fb084SSoby Mathew } else { 408319fb084SSoby Mathew /* This is the only other error code we expect */ 409319fb084SSoby Mathew assert(error == -EPERM); 410dc65ae46SJavier Almansa Sobrino ret = E_RMM_BAD_PAS; 411319fb084SSoby Mathew } 412319fb084SSoby Mathew 413319fb084SSoby Mathew ERROR("RMMD: PAS Transition failed. GPT ret = %d, PA: 0x%"PRIx64 ", FID = 0x%x\n", 414319fb084SSoby Mathew error, address, smc_fid); 415319fb084SSoby Mathew return ret; 416319fb084SSoby Mathew } 417319fb084SSoby Mathew 41877c27753SZelalem Aweke /******************************************************************************* 419319fb084SSoby Mathew * This function handles RMM-EL3 interface SMCs 42077c27753SZelalem Aweke ******************************************************************************/ 421319fb084SSoby Mathew uint64_t rmmd_rmm_el3_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, 42277c27753SZelalem Aweke uint64_t x3, uint64_t x4, void *cookie, 42377c27753SZelalem Aweke void *handle, uint64_t flags) 42477c27753SZelalem Aweke { 42577c27753SZelalem Aweke uint32_t src_sec_state; 4266a00e9b0SRobert Wakim int ret; 42777c27753SZelalem Aweke 4288c980a4aSJavier Almansa Sobrino /* If RMM failed to boot, treat any RMM-EL3 interface SMC as unknown */ 4298c980a4aSJavier Almansa Sobrino if (rmm_boot_failed) { 4308c980a4aSJavier Almansa Sobrino WARN("RMMD: Failed to boot up RMM. Ignoring RMM-EL3 call\n"); 4318c980a4aSJavier Almansa Sobrino SMC_RET1(handle, SMC_UNK); 4328c980a4aSJavier Almansa Sobrino } 4338c980a4aSJavier Almansa Sobrino 43477c27753SZelalem Aweke /* Determine which security state this SMC originated from */ 43577c27753SZelalem Aweke src_sec_state = caller_sec_state(flags); 43677c27753SZelalem Aweke 43777c27753SZelalem Aweke if (src_sec_state != SMC_FROM_REALM) { 438319fb084SSoby Mathew WARN("RMMD: RMM-EL3 call originated from secure or normal world\n"); 43977c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 44077c27753SZelalem Aweke } 44177c27753SZelalem Aweke 44277c27753SZelalem Aweke switch (smc_fid) { 443e50fedbcSJavier Almansa Sobrino case RMM_GTSI_DELEGATE: 4446a00e9b0SRobert Wakim ret = gpt_delegate_pas(x1, PAGE_SIZE_4KB, SMC_FROM_REALM); 445319fb084SSoby Mathew SMC_RET1(handle, gpt_to_gts_error(ret, smc_fid, x1)); 446e50fedbcSJavier Almansa Sobrino case RMM_GTSI_UNDELEGATE: 4476a00e9b0SRobert Wakim ret = gpt_undelegate_pas(x1, PAGE_SIZE_4KB, SMC_FROM_REALM); 448319fb084SSoby Mathew SMC_RET1(handle, gpt_to_gts_error(ret, smc_fid, x1)); 449e50fedbcSJavier Almansa Sobrino case RMM_ATTEST_GET_PLAT_TOKEN: 4500f9159b7SSoby Mathew ret = rmmd_attest_get_platform_token(x1, &x2, x3); 4510f9159b7SSoby Mathew SMC_RET2(handle, ret, x2); 452e50fedbcSJavier Almansa Sobrino case RMM_ATTEST_GET_REALM_KEY: 453a0435105SSoby Mathew ret = rmmd_attest_get_signing_key(x1, &x2, x3); 454a0435105SSoby Mathew SMC_RET2(handle, ret, x2); 4558c980a4aSJavier Almansa Sobrino 4568c980a4aSJavier Almansa Sobrino case RMM_BOOT_COMPLETE: 4578c980a4aSJavier Almansa Sobrino VERBOSE("RMMD: running rmmd_rmm_sync_exit\n"); 4588c980a4aSJavier Almansa Sobrino rmmd_rmm_sync_exit(x1); 4598c980a4aSJavier Almansa Sobrino 46077c27753SZelalem Aweke default: 461319fb084SSoby Mathew WARN("RMMD: Unsupported RMM-EL3 call 0x%08x\n", smc_fid); 46277c27753SZelalem Aweke SMC_RET1(handle, SMC_UNK); 46377c27753SZelalem Aweke } 46477c27753SZelalem Aweke } 465