diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/arm_arch_svc/arm_arch_svc_setup.c | 26 | ||||
-rw-r--r-- | services/spd/trusty/trusty.c | 10 | ||||
-rw-r--r-- | services/std_svc/rmmd/aarch64/rmmd_helpers.S | 73 | ||||
-rw-r--r-- | services/std_svc/rmmd/rmmd.mk | 18 | ||||
-rw-r--r-- | services/std_svc/rmmd/rmmd_initial_context.h | 33 | ||||
-rw-r--r-- | services/std_svc/rmmd/rmmd_main.c | 347 | ||||
-rw-r--r-- | services/std_svc/rmmd/rmmd_private.h | 64 | ||||
-rw-r--r-- | services/std_svc/rmmd/trp/linker.lds | 71 | ||||
-rw-r--r-- | services/std_svc/rmmd/trp/trp.mk | 20 | ||||
-rw-r--r-- | services/std_svc/rmmd/trp/trp_entry.S | 74 | ||||
-rw-r--r-- | services/std_svc/rmmd/trp/trp_main.c | 136 | ||||
-rw-r--r-- | services/std_svc/rmmd/trp/trp_private.h | 50 | ||||
-rw-r--r-- | services/std_svc/sdei/sdei_intr_mgmt.c | 12 | ||||
-rw-r--r-- | services/std_svc/sdei/sdei_main.c | 72 | ||||
-rw-r--r-- | services/std_svc/spm_mm/spm_mm.mk | 6 | ||||
-rw-r--r-- | services/std_svc/spmd/spmd.mk | 8 | ||||
-rw-r--r-- | services/std_svc/spmd/spmd_main.c | 167 | ||||
-rw-r--r-- | services/std_svc/spmd/spmd_pm.c | 25 | ||||
-rw-r--r-- | services/std_svc/spmd/spmd_private.h | 1 | ||||
-rw-r--r-- | services/std_svc/std_svc_setup.c | 12 |
20 files changed, 1131 insertions, 94 deletions
diff --git a/services/arm_arch_svc/arm_arch_svc_setup.c b/services/arm_arch_svc/arm_arch_svc_setup.c index 37bfc62e2..1d4423cb3 100644 --- a/services/arm_arch_svc/arm_arch_svc_setup.c +++ b/services/arm_arch_svc/arm_arch_svc_setup.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ @@ -11,9 +11,19 @@ #include <lib/cpus/wa_cve_2018_3639.h> #include <lib/smccc.h> #include <services/arm_arch_svc.h> +#include <services/rmi_svc.h> +#include <services/rmmd_svc.h> #include <smccc_helpers.h> #include <plat/common/platform.h> +#if ENABLE_RME +/* Setup Arm architecture Services */ +static int32_t arm_arch_svc_setup(void) +{ + return rmmd_setup(); +} +#endif + static int32_t smccc_version(void) { return MAKE_SMCCC_VERSION(SMCCC_MAJOR_VERSION, SMCCC_MINOR_VERSION); @@ -133,6 +143,16 @@ static uintptr_t arm_arch_svc_smc_handler(uint32_t smc_fid, SMC_RET0(handle); #endif default: +#if ENABLE_RME + /* + * RMI functions are allocated from the Arch service range. Call + * the RMM dispatcher to handle RMI calls. + */ + if (is_rmi_fid(smc_fid)) { + return rmmd_rmi_handler(smc_fid, x1, x2, x3, x4, cookie, + handle, flags); + } +#endif WARN("Unimplemented Arm Architecture Service Call: 0x%x \n", smc_fid); SMC_RET1(handle, SMC_UNK); @@ -145,6 +165,10 @@ DECLARE_RT_SVC( OEN_ARM_START, OEN_ARM_END, SMC_TYPE_FAST, +#if ENABLE_RME + arm_arch_svc_setup, +#else NULL, +#endif arm_arch_svc_smc_handler ); diff --git a/services/spd/trusty/trusty.c b/services/spd/trusty/trusty.c index e102b8228..7daebcdd1 100644 --- a/services/spd/trusty/trusty.c +++ b/services/spd/trusty/trusty.c @@ -6,8 +6,10 @@ */ #include <assert.h> +#include <inttypes.h> #include <lib/xlat_tables/xlat_tables_v2.h> #include <stdbool.h> +#include <stdint.h> #include <string.h> #include <arch_helpers.h> @@ -172,7 +174,7 @@ static uint64_t trusty_set_fiq_handler(void *handle, uint64_t cpu, struct trusty_cpu_ctx *ctx; if (cpu >= (uint64_t)PLATFORM_CORE_COUNT) { - ERROR("%s: cpu %lld >= %d\n", __func__, cpu, PLATFORM_CORE_COUNT); + ERROR("%s: cpu %" PRId64 " >= %d\n", __func__, cpu, PLATFORM_CORE_COUNT); return (uint64_t)SM_ERR_INVALID_PARAMETERS; } @@ -204,7 +206,7 @@ static uint64_t trusty_fiq_exit(void *handle, uint64_t x1, uint64_t x2, uint64_t ret = trusty_context_switch(NON_SECURE, SMC_FC_FIQ_EXIT, 0, 0, 0); if (ret.r0 != 1U) { - INFO("%s(%p) SMC_FC_FIQ_EXIT returned unexpected value, %lld\n", + INFO("%s(%p) SMC_FC_FIQ_EXIT returned unexpected value, %" PRId64 "\n", __func__, handle, ret.r0); } @@ -356,7 +358,7 @@ static void trusty_cpu_suspend(uint32_t off) ret = trusty_context_switch(NON_SECURE, SMC_FC_CPU_SUSPEND, off, 0, 0); if (ret.r0 != 0U) { - INFO("%s: cpu %d, SMC_FC_CPU_SUSPEND returned unexpected value, %lld\n", + INFO("%s: cpu %d, SMC_FC_CPU_SUSPEND returned unexpected value, %" PRId64 "\n", __func__, plat_my_core_pos(), ret.r0); } } @@ -367,7 +369,7 @@ static void trusty_cpu_resume(uint32_t on) ret = trusty_context_switch(NON_SECURE, SMC_FC_CPU_RESUME, on, 0, 0); if (ret.r0 != 0U) { - INFO("%s: cpu %d, SMC_FC_CPU_RESUME returned unexpected value, %lld\n", + INFO("%s: cpu %d, SMC_FC_CPU_RESUME returned unexpected value, %" PRId64 "\n", __func__, plat_my_core_pos(), ret.r0); } } diff --git a/services/std_svc/rmmd/aarch64/rmmd_helpers.S b/services/std_svc/rmmd/aarch64/rmmd_helpers.S new file mode 100644 index 000000000..6229baf4d --- /dev/null +++ b/services/std_svc/rmmd/aarch64/rmmd_helpers.S @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "../rmmd_private.h" +#include <asm_macros.S> + + .global rmmd_rmm_enter + .global rmmd_rmm_exit + + /* --------------------------------------------------------------------- + * This function is called with SP_EL0 as stack. Here we stash our EL3 + * callee-saved registers on to the stack as a part of saving the C + * runtime and enter the secure payload. + * 'x0' contains a pointer to the memory where the address of the C + * runtime context is to be saved. + * --------------------------------------------------------------------- + */ +func rmmd_rmm_enter + /* Make space for the registers that we're going to save */ + mov x3, sp + str x3, [x0, #0] + sub sp, sp, #RMMD_C_RT_CTX_SIZE + + /* Save callee-saved registers on to the stack */ + stp x19, x20, [sp, #RMMD_C_RT_CTX_X19] + stp x21, x22, [sp, #RMMD_C_RT_CTX_X21] + stp x23, x24, [sp, #RMMD_C_RT_CTX_X23] + stp x25, x26, [sp, #RMMD_C_RT_CTX_X25] + stp x27, x28, [sp, #RMMD_C_RT_CTX_X27] + stp x29, x30, [sp, #RMMD_C_RT_CTX_X29] + + /* --------------------------------------------------------------------- + * Everything is setup now. el3_exit() will use the secure context to + * restore to the general purpose and EL3 system registers to ERET + * into the secure payload. + * --------------------------------------------------------------------- + */ + b el3_exit +endfunc rmmd_rmm_enter + + /* --------------------------------------------------------------------- + * This function is called with 'x0' pointing to a C runtime context. + * It restores the saved registers and jumps to that runtime with 'x0' + * as the new SP register. This destroys the C runtime context that had + * been built on the stack below the saved context by the caller. Later + * the second parameter 'x1' is passed as a return value to the caller. + * --------------------------------------------------------------------- + */ +func rmmd_rmm_exit + /* Restore the previous stack */ + mov sp, x0 + + /* Restore callee-saved registers on to the stack */ + ldp x19, x20, [x0, #(RMMD_C_RT_CTX_X19 - RMMD_C_RT_CTX_SIZE)] + ldp x21, x22, [x0, #(RMMD_C_RT_CTX_X21 - RMMD_C_RT_CTX_SIZE)] + ldp x23, x24, [x0, #(RMMD_C_RT_CTX_X23 - RMMD_C_RT_CTX_SIZE)] + ldp x25, x26, [x0, #(RMMD_C_RT_CTX_X25 - RMMD_C_RT_CTX_SIZE)] + ldp x27, x28, [x0, #(RMMD_C_RT_CTX_X27 - RMMD_C_RT_CTX_SIZE)] + ldp x29, x30, [x0, #(RMMD_C_RT_CTX_X29 - RMMD_C_RT_CTX_SIZE)] + + /* --------------------------------------------------------------------- + * This should take us back to the instruction after the call to the + * last rmmd_rmm_enter().* Place the second parameter to x0 + * so that the caller will see it as a return value from the original + * entry call. + * --------------------------------------------------------------------- + */ + mov x0, x1 + ret +endfunc rmmd_rmm_exit diff --git a/services/std_svc/rmmd/rmmd.mk b/services/std_svc/rmmd/rmmd.mk new file mode 100644 index 000000000..bac0a9f28 --- /dev/null +++ b/services/std_svc/rmmd/rmmd.mk @@ -0,0 +1,18 @@ +# +# Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +ifneq (${ARCH},aarch64) + $(error "Error: RMMD is only supported on aarch64.") +endif + +include services/std_svc/rmmd/trp/trp.mk + +RMMD_SOURCES += $(addprefix services/std_svc/rmmd/, \ + ${ARCH}/rmmd_helpers.S \ + rmmd_main.c) + +# Let the top-level Makefile know that we intend to include RMM image +NEED_RMM := yes diff --git a/services/std_svc/rmmd/rmmd_initial_context.h b/services/std_svc/rmmd/rmmd_initial_context.h new file mode 100644 index 000000000..d7a743d8e --- /dev/null +++ b/services/std_svc/rmmd/rmmd_initial_context.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RMMD_INITIAL_CONTEXT_H +#define RMMD_INITIAL_CONTEXT_H + +#include <arch.h> + +/* + * SPSR_EL2 + * M=0x9 (0b1001 EL2h) + * M[4]=0 + * DAIF=0xF Exceptions masked on entry. + * BTYPE=0 BTI not yet supported. + * SSBS=0 Not yet supported. + * IL=0 Not an illegal exception return. + * SS=0 Not single stepping. + * PAN=1 RMM shouldn't access realm memory. + * UAO=0 + * DIT=0 + * TCO=0 + * NZCV=0 + */ +#define REALM_SPSR_EL2 ( \ + SPSR_M_EL2H | \ + (0xF << SPSR_DAIF_SHIFT) | \ + SPSR_PAN_BIT \ + ) + +#endif /* RMMD_INITIAL_CONTEXT_H */ diff --git a/services/std_svc/rmmd/rmmd_main.c b/services/std_svc/rmmd/rmmd_main.c new file mode 100644 index 000000000..7f85b636f --- /dev/null +++ b/services/std_svc/rmmd/rmmd_main.c @@ -0,0 +1,347 @@ +/* + * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> +#include <inttypes.h> +#include <stdint.h> +#include <string.h> + +#include <arch_helpers.h> +#include <arch_features.h> +#include <bl31/bl31.h> +#include <common/debug.h> +#include <common/runtime_svc.h> +#include <context.h> +#include <lib/el3_runtime/context_mgmt.h> +#include <lib/el3_runtime/pubsub.h> +#include <lib/gpt_rme/gpt_rme.h> + +#include <lib/spinlock.h> +#include <lib/utils.h> +#include <lib/xlat_tables/xlat_tables_v2.h> +#include <plat/common/common_def.h> +#include <plat/common/platform.h> +#include <platform_def.h> +#include <services/gtsi_svc.h> +#include <services/rmi_svc.h> +#include <services/rmmd_svc.h> +#include <smccc_helpers.h> +#include "rmmd_initial_context.h" +#include "rmmd_private.h" + +/******************************************************************************* + * RMM context information. + ******************************************************************************/ +rmmd_rmm_context_t rmm_context[PLATFORM_CORE_COUNT]; + +/******************************************************************************* + * RMM entry point information. Discovered on the primary core and reused + * on secondary cores. + ******************************************************************************/ +static entry_point_info_t *rmm_ep_info; + +/******************************************************************************* + * Static function declaration. + ******************************************************************************/ +static int32_t rmm_init(void); +static uint64_t rmmd_smc_forward(uint32_t smc_fid, uint32_t src_sec_state, + uint32_t dst_sec_state, uint64_t x1, + uint64_t x2, uint64_t x3, uint64_t x4, + void *handle); + +/******************************************************************************* + * This function takes an RMM context pointer and performs a synchronous entry + * into it. + ******************************************************************************/ +uint64_t rmmd_rmm_sync_entry(rmmd_rmm_context_t *rmm_ctx) +{ + uint64_t rc; + + assert(rmm_ctx != NULL); + + cm_set_context(&(rmm_ctx->cpu_ctx), REALM); + + /* Save the current el1/el2 context before loading realm context. */ + cm_el1_sysregs_context_save(NON_SECURE); + cm_el2_sysregs_context_save(NON_SECURE); + + /* Restore the realm context assigned above */ + cm_el1_sysregs_context_restore(REALM); + cm_el2_sysregs_context_restore(REALM); + cm_set_next_eret_context(REALM); + + /* Enter RMM */ + rc = rmmd_rmm_enter(&rmm_ctx->c_rt_ctx); + + /* Save realm context */ + cm_el1_sysregs_context_save(REALM); + cm_el2_sysregs_context_save(REALM); + + /* Restore the el1/el2 context again. */ + cm_el1_sysregs_context_restore(NON_SECURE); + cm_el2_sysregs_context_restore(NON_SECURE); + + return rc; +} + +/******************************************************************************* + * This function returns to the place where rmmd_rmm_sync_entry() was + * called originally. + ******************************************************************************/ +__dead2 void rmmd_rmm_sync_exit(uint64_t rc) +{ + rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()]; + + /* Get context of the RMM in use by this CPU. */ + assert(cm_get_context(REALM) == &(ctx->cpu_ctx)); + + /* + * The RMMD must have initiated the original request through a + * synchronous entry into RMM. Jump back to the original C runtime + * context with the value of rc in x0; + */ + rmmd_rmm_exit(ctx->c_rt_ctx, rc); + + panic(); +} + +static void rmm_el2_context_init(el2_sysregs_t *regs) +{ + regs->ctx_regs[CTX_SPSR_EL2 >> 3] = REALM_SPSR_EL2; + regs->ctx_regs[CTX_SCTLR_EL2 >> 3] = SCTLR_EL2_RES1; +} + +/******************************************************************************* + * Jump to the RMM for the first time. + ******************************************************************************/ +static int32_t rmm_init(void) +{ + + uint64_t rc; + + rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()]; + + INFO("RMM init start.\n"); + ctx->state = RMM_STATE_RESET; + + /* Initialize RMM EL2 context. */ + rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx); + + rc = rmmd_rmm_sync_entry(ctx); + if (rc != 0ULL) { + ERROR("RMM initialisation failed 0x%" PRIx64 "\n", rc); + panic(); + } + + ctx->state = RMM_STATE_IDLE; + INFO("RMM init end.\n"); + + return 1; +} + +/******************************************************************************* + * Load and read RMM manifest, setup RMM. + ******************************************************************************/ +int rmmd_setup(void) +{ + uint32_t ep_attr; + unsigned int linear_id = plat_my_core_pos(); + rmmd_rmm_context_t *rmm_ctx = &rmm_context[linear_id]; + + /* Make sure RME is supported. */ + assert(get_armv9_2_feat_rme_support() != 0U); + + rmm_ep_info = bl31_plat_get_next_image_ep_info(REALM); + if (rmm_ep_info == NULL) { + WARN("No RMM image provided by BL2 boot loader, Booting " + "device without RMM initialization. SMCs destined for " + "RMM will return SMC_UNK\n"); + return -ENOENT; + } + + /* Under no circumstances will this parameter be 0 */ + assert(rmm_ep_info->pc == RMM_BASE); + + /* Initialise an entrypoint to set up the CPU context */ + ep_attr = EP_REALM; + if ((read_sctlr_el3() & SCTLR_EE_BIT) != 0U) { + ep_attr |= EP_EE_BIG; + } + + SET_PARAM_HEAD(rmm_ep_info, PARAM_EP, VERSION_1, ep_attr); + rmm_ep_info->spsr = SPSR_64(MODE_EL2, + MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS); + + /* Initialise RMM context with this entry point information */ + cm_setup_context(&rmm_ctx->cpu_ctx, rmm_ep_info); + + INFO("RMM setup done.\n"); + + /* Register init function for deferred init. */ + bl31_register_rmm_init(&rmm_init); + + return 0; +} + +/******************************************************************************* + * Forward SMC to the other security state + ******************************************************************************/ +static uint64_t rmmd_smc_forward(uint32_t smc_fid, uint32_t src_sec_state, + uint32_t dst_sec_state, uint64_t x1, + uint64_t x2, uint64_t x3, uint64_t x4, + void *handle) +{ + /* Save incoming security state */ + cm_el1_sysregs_context_save(src_sec_state); + cm_el2_sysregs_context_save(src_sec_state); + + /* Restore outgoing security state */ + cm_el1_sysregs_context_restore(dst_sec_state); + cm_el2_sysregs_context_restore(dst_sec_state); + cm_set_next_eret_context(dst_sec_state); + + SMC_RET8(cm_get_context(dst_sec_state), smc_fid, x1, x2, x3, x4, + SMC_GET_GP(handle, CTX_GPREG_X5), + SMC_GET_GP(handle, CTX_GPREG_X6), + SMC_GET_GP(handle, CTX_GPREG_X7)); +} + +/******************************************************************************* + * This function handles all SMCs in the range reserved for RMI. Each call is + * either forwarded to the other security state or handled by the RMM dispatcher + ******************************************************************************/ +uint64_t rmmd_rmi_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, + uint64_t x3, uint64_t x4, void *cookie, + void *handle, uint64_t flags) +{ + rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()]; + uint32_t src_sec_state; + + /* Determine which security state this SMC originated from */ + src_sec_state = caller_sec_state(flags); + + /* RMI must not be invoked by the Secure world */ + if (src_sec_state == SMC_FROM_SECURE) { + WARN("RMM: RMI invoked by secure world.\n"); + SMC_RET1(handle, SMC_UNK); + } + + /* + * Forward an RMI call from the Normal world to the Realm world as it + * is. + */ + if (src_sec_state == SMC_FROM_NON_SECURE) { + VERBOSE("RMM: RMI call from non-secure world.\n"); + return rmmd_smc_forward(smc_fid, NON_SECURE, REALM, + x1, x2, x3, x4, handle); + } + + assert(src_sec_state == SMC_FROM_REALM); + + switch (smc_fid) { + case RMI_RMM_REQ_COMPLETE: + if (ctx->state == RMM_STATE_RESET) { + VERBOSE("RMM: running rmmd_rmm_sync_exit\n"); + rmmd_rmm_sync_exit(x1); + } + + return rmmd_smc_forward(x1, REALM, NON_SECURE, + x2, x3, x4, 0, handle); + + default: + WARN("RMM: Unsupported RMM call 0x%08x\n", smc_fid); + SMC_RET1(handle, SMC_UNK); + } +} + +/******************************************************************************* + * This cpu has been turned on. Enter RMM to initialise R-EL2. Entry into RMM + * is done after initialising minimal architectural state that guarantees safe + * execution. + ******************************************************************************/ +static void *rmmd_cpu_on_finish_handler(const void *arg) +{ + int32_t rc; + uint32_t linear_id = plat_my_core_pos(); + rmmd_rmm_context_t *ctx = &rmm_context[linear_id]; + + ctx->state = RMM_STATE_RESET; + + /* Initialise RMM context with this entry point information */ + cm_setup_context(&ctx->cpu_ctx, rmm_ep_info); + + /* Initialize RMM EL2 context. */ + rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx); + + rc = rmmd_rmm_sync_entry(ctx); + if (rc != 0) { + ERROR("RMM initialisation failed (%d) on CPU%d\n", rc, + linear_id); + panic(); + } + + ctx->state = RMM_STATE_IDLE; + return NULL; +} + +/* Subscribe to PSCI CPU on to initialize RMM on secondary */ +SUBSCRIBE_TO_EVENT(psci_cpu_on_finish, rmmd_cpu_on_finish_handler); + +static int gtsi_transition_granule(uint64_t pa, + unsigned int src_sec_state, + unsigned int target_pas) +{ + int ret; + + ret = gpt_transition_pas(pa, PAGE_SIZE_4KB, src_sec_state, target_pas); + + /* Convert TF-A error codes into GTSI error codes */ + if (ret == -EINVAL) { + ERROR("[GTSI] Transition failed: invalid %s\n", "address"); + ERROR(" PA: 0x%" PRIx64 ", SRC: %d, PAS: %d\n", pa, + src_sec_state, target_pas); + ret = GRAN_TRANS_RET_BAD_ADDR; + } else if (ret == -EPERM) { + ERROR("[GTSI] Transition failed: invalid %s\n", "caller/PAS"); + ERROR(" PA: 0x%" PRIx64 ", SRC: %d, PAS: %d\n", pa, + src_sec_state, target_pas); + ret = GRAN_TRANS_RET_BAD_PAS; + } + + return ret; +} + +/******************************************************************************* + * This function handles all SMCs in the range reserved for GTF. + ******************************************************************************/ +uint64_t rmmd_gtsi_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, + uint64_t x3, uint64_t x4, void *cookie, + void *handle, uint64_t flags) +{ + uint32_t src_sec_state; + + /* Determine which security state this SMC originated from */ + src_sec_state = caller_sec_state(flags); + + if (src_sec_state != SMC_FROM_REALM) { + WARN("RMM: GTF call originated from secure or normal world\n"); + SMC_RET1(handle, SMC_UNK); + } + + switch (smc_fid) { + case SMC_ASC_MARK_REALM: + SMC_RET1(handle, gtsi_transition_granule(x1, SMC_FROM_REALM, + GPT_GPI_REALM)); + case SMC_ASC_MARK_NONSECURE: + SMC_RET1(handle, gtsi_transition_granule(x1, SMC_FROM_REALM, + GPT_GPI_NS)); + default: + WARN("RMM: Unsupported GTF call 0x%08x\n", smc_fid); + SMC_RET1(handle, SMC_UNK); + } +} diff --git a/services/std_svc/rmmd/rmmd_private.h b/services/std_svc/rmmd/rmmd_private.h new file mode 100644 index 000000000..d170bcd22 --- /dev/null +++ b/services/std_svc/rmmd/rmmd_private.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef RMMD_PRIVATE_H +#define RMMD_PRIVATE_H + +#include <context.h> + +/******************************************************************************* + * Constants that allow assembler code to preserve callee-saved registers of the + * C runtime context while performing a security state switch. + ******************************************************************************/ +#define RMMD_C_RT_CTX_X19 0x0 +#define RMMD_C_RT_CTX_X20 0x8 +#define RMMD_C_RT_CTX_X21 0x10 +#define RMMD_C_RT_CTX_X22 0x18 +#define RMMD_C_RT_CTX_X23 0x20 +#define RMMD_C_RT_CTX_X24 0x28 +#define RMMD_C_RT_CTX_X25 0x30 +#define RMMD_C_RT_CTX_X26 0x38 +#define RMMD_C_RT_CTX_X27 0x40 +#define RMMD_C_RT_CTX_X28 0x48 +#define RMMD_C_RT_CTX_X29 0x50 +#define RMMD_C_RT_CTX_X30 0x58 + +#define RMMD_C_RT_CTX_SIZE 0x60 +#define RMMD_C_RT_CTX_ENTRIES (RMMD_C_RT_CTX_SIZE >> DWORD_SHIFT) + +#ifndef __ASSEMBLER__ +#include <stdint.h> +#include <services/rmi_svc.h> + +typedef enum rmm_state { + RMM_STATE_RESET = 0, + RMM_STATE_IDLE +} rmm_state_t; + +/* + * Data structure used by the RMM dispatcher (RMMD) in EL3 to track context of + * the RMM at R-EL2. + */ +typedef struct rmmd_rmm_context { + uint64_t c_rt_ctx; + cpu_context_t cpu_ctx; + rmm_state_t state; +} rmmd_rmm_context_t; + +/* Functions used to enter/exit the RMM synchronously */ +uint64_t rmmd_rmm_sync_entry(rmmd_rmm_context_t *ctx); +__dead2 void rmmd_rmm_sync_exit(uint64_t rc); + +/* Assembly helpers */ +uint64_t rmmd_rmm_enter(uint64_t *c_rt_ctx); +void __dead2 rmmd_rmm_exit(uint64_t c_rt_ctx, uint64_t ret); + +/* Reference to PM ops for the RMMD */ +extern const spd_pm_ops_t rmmd_pm; + +#endif /* __ASSEMBLER__ */ + +#endif /* RMMD_PRIVATE_H */ diff --git a/services/std_svc/rmmd/trp/linker.lds b/services/std_svc/rmmd/trp/linker.lds new file mode 100644 index 000000000..2b7f38333 --- /dev/null +++ b/services/std_svc/rmmd/trp/linker.lds @@ -0,0 +1,71 @@ +/* + * (C) COPYRIGHT 2021 Arm Limited or its affiliates. + * ALL RIGHTS RESERVED + */ + +#include <common/bl_common.ld.h> +#include <lib/xlat_tables/xlat_tables_defs.h> + +/* Mapped using 4K pages, requires us to align different sections with + * different property at the same granularity. */ +PAGE_SIZE_4K = 4096; + +OUTPUT_FORMAT("elf64-littleaarch64") +OUTPUT_ARCH(aarch64) +ENTRY(trp_head) + +MEMORY { + RAM (rwx): ORIGIN = RMM_BASE, LENGTH = RMM_LIMIT - RMM_BASE +} + + +SECTIONS +{ + . = RMM_BASE; + + .text : { + *(.head.text) + . = ALIGN(8); + *(.text*) + } >RAM + + . = ALIGN(PAGE_SIZE_4K); + + .rodata : { + *(.rodata*) + } >RAM + + . = ALIGN(PAGE_SIZE_4K); + + __RW_START__ = . ; + + .data : { + *(.data*) + } >RAM + + .bss (NOLOAD) : { + __BSS_START__ = .; + *(.bss*) + __BSS_END__ = .; + } >RAM + __BSS_SIZE__ = SIZEOF(.bss); + + + STACK_SECTION >RAM + + + /* + * Define a linker symbol to mark the end of the RW memory area for this + * image. + */ + __RW_END__ = .; + __RMM_END__ = .; + + + /DISCARD/ : { *(.dynstr*) } + /DISCARD/ : { *(.dynamic*) } + /DISCARD/ : { *(.plt*) } + /DISCARD/ : { *(.interp*) } + /DISCARD/ : { *(.gnu*) } + /DISCARD/ : { *(.note*) } +} diff --git a/services/std_svc/rmmd/trp/trp.mk b/services/std_svc/rmmd/trp/trp.mk new file mode 100644 index 000000000..a4f6e03e0 --- /dev/null +++ b/services/std_svc/rmmd/trp/trp.mk @@ -0,0 +1,20 @@ +# +# Copyright (c) 2021 Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +RMM_SOURCES += services/std_svc/rmmd/trp/trp_entry.S \ + services/std_svc/rmmd/trp/trp_main.c + +RMM_LINKERFILE := services/std_svc/rmmd/trp/linker.lds + +# Include the platform-specific TRP Makefile +# If no platform-specific TRP Makefile exists, it means TRP is not supported +# on this platform. +TRP_PLAT_MAKEFILE := $(wildcard ${PLAT_DIR}/trp/trp-${PLAT}.mk) +ifeq (,${TRP_PLAT_MAKEFILE}) + $(error TRP is not supported on platform ${PLAT}) +else + include ${TRP_PLAT_MAKEFILE} +endif diff --git a/services/std_svc/rmmd/trp/trp_entry.S b/services/std_svc/rmmd/trp/trp_entry.S new file mode 100644 index 000000000..23b48fb42 --- /dev/null +++ b/services/std_svc/rmmd/trp/trp_entry.S @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <asm_macros.S> +#include <services/gtsi_svc.h> +#include <services/rmi_svc.h> +#include "trp_private.h" + +.global trp_head +.global trp_smc + +.section ".head.text", "ax" + + /* --------------------------------------------- + * Populate the params in x0-x7 from the pointer + * to the smc args structure in x0. + * --------------------------------------------- + */ + .macro restore_args_call_smc + ldp x6, x7, [x0, #TRP_ARG6] + ldp x4, x5, [x0, #TRP_ARG4] + ldp x2, x3, [x0, #TRP_ARG2] + ldp x0, x1, [x0, #TRP_ARG0] + smc #0 + .endm + + /* --------------------------------------------- + * Entry point for TRP + * --------------------------------------------- + */ +trp_head: + bl plat_set_my_stack + bl plat_is_my_cpu_primary + cbz x0, trp_secondary_cpu_entry + + /* --------------------------------------------- + * Zero out BSS section + * --------------------------------------------- + */ + ldr x0, =__BSS_START__ + ldr x1, =__BSS_SIZE__ + bl zeromem + + bl trp_setup + + bl trp_main +trp_secondary_cpu_entry: + mov_imm x0, RMI_RMM_REQ_COMPLETE + mov x1, xzr + smc #0 + b trp_handler + + /* --------------------------------------------- + * Direct SMC call to BL31 service provided by + * RMM Dispatcher + * --------------------------------------------- + */ +func trp_smc + restore_args_call_smc + ret +endfunc trp_smc + + /* --------------------------------------------- + * RMI call handler + * --------------------------------------------- + */ +func trp_handler + bl trp_rmi_handler + restore_args_call_smc + b trp_handler +endfunc trp_handler diff --git a/services/std_svc/rmmd/trp/trp_main.c b/services/std_svc/rmmd/trp/trp_main.c new file mode 100644 index 000000000..2ab9eccfd --- /dev/null +++ b/services/std_svc/rmmd/trp/trp_main.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +#include <common/debug.h> +#include <plat/common/platform.h> +#include <services/gtsi_svc.h> +#include <services/rmi_svc.h> +#include <services/trp/platform_trp.h> + +#include <platform_def.h> +#include "trp_private.h" + +/******************************************************************************* + * Per cpu data structure to populate parameters for an SMC in C code and use + * a pointer to this structure in assembler code to populate x0-x7 + ******************************************************************************/ +static trp_args_t trp_smc_args[PLATFORM_CORE_COUNT]; + +/******************************************************************************* + * Set the arguments for SMC call + ******************************************************************************/ +static trp_args_t *set_smc_args(uint64_t arg0, + uint64_t arg1, + uint64_t arg2, + uint64_t arg3, + uint64_t arg4, + uint64_t arg5, + uint64_t arg6, + uint64_t arg7) +{ + uint32_t linear_id; + trp_args_t *pcpu_smc_args; + + /* + * Return to Secure Monitor by raising an SMC. The results of the + * service are passed as an arguments to the SMC + */ + linear_id = plat_my_core_pos(); + pcpu_smc_args = &trp_smc_args[linear_id]; + write_trp_arg(pcpu_smc_args, TRP_ARG0, arg0); + write_trp_arg(pcpu_smc_args, TRP_ARG1, arg1); + write_trp_arg(pcpu_smc_args, TRP_ARG2, arg2); + write_trp_arg(pcpu_smc_args, TRP_ARG3, arg3); + write_trp_arg(pcpu_smc_args, TRP_ARG4, arg4); + write_trp_arg(pcpu_smc_args, TRP_ARG5, arg5); + write_trp_arg(pcpu_smc_args, TRP_ARG6, arg6); + write_trp_arg(pcpu_smc_args, TRP_ARG7, arg7); + + return pcpu_smc_args; +} + +/******************************************************************************* + * Setup function for TRP. + ******************************************************************************/ +void trp_setup(void) +{ + /* Perform early platform-specific setup */ + trp_early_platform_setup(); +} + +/* Main function for TRP */ +void trp_main(void) +{ + NOTICE("TRP: %s\n", version_string); + NOTICE("TRP: %s\n", build_message); + INFO("TRP: Memory base : 0x%lx\n", (unsigned long)RMM_BASE); + INFO("TRP: Total size : 0x%lx bytes\n", (unsigned long)(RMM_END + - RMM_BASE)); +} + +/******************************************************************************* + * Returning RMI version back to Normal World + ******************************************************************************/ +static trp_args_t *trp_ret_rmi_version(void) +{ + VERBOSE("RMM version is %u.%u\n", RMI_ABI_VERSION_MAJOR, + RMI_ABI_VERSION_MINOR); + return set_smc_args(RMI_RMM_REQ_COMPLETE, RMI_ABI_VERSION, + 0, 0, 0, 0, 0, 0); +} + +/******************************************************************************* + * Transitioning granule of NON-SECURE type to REALM type + ******************************************************************************/ +static trp_args_t *trp_asc_mark_realm(unsigned long long x1) +{ + unsigned long long ret; + + VERBOSE("Delegating granule 0x%llx\n", x1); + ret = trp_smc(set_smc_args(SMC_ASC_MARK_REALM, x1, 0, 0, 0, 0, 0, 0)); + + if (ret != 0ULL) { + ERROR("Granule transition from NON-SECURE type to REALM type " + "failed 0x%llx\n", ret); + } + return set_smc_args(RMI_RMM_REQ_COMPLETE, ret, 0, 0, 0, 0, 0, 0); +} + +/******************************************************************************* + * Transitioning granule of REALM type to NON-SECURE type + ******************************************************************************/ +static trp_args_t *trp_asc_mark_nonsecure(unsigned long long x1) +{ + unsigned long long ret; + + VERBOSE("Undelegating granule 0x%llx\n", x1); + ret = trp_smc(set_smc_args(SMC_ASC_MARK_NONSECURE, x1, 0, 0, 0, 0, 0, 0)); + + if (ret != 0ULL) { + ERROR("Granule transition from REALM type to NON-SECURE type " + "failed 0x%llx\n", ret); + } + return set_smc_args(RMI_RMM_REQ_COMPLETE, ret, 0, 0, 0, 0, 0, 0); +} + +/******************************************************************************* + * Main RMI SMC handler function + ******************************************************************************/ +trp_args_t *trp_rmi_handler(unsigned long fid, unsigned long long x1) +{ + switch (fid) { + case RMI_RMM_REQ_VERSION: + return trp_ret_rmi_version(); + case RMI_RMM_GRANULE_DELEGATE: + return trp_asc_mark_realm(x1); + case RMI_RMM_GRANULE_UNDELEGATE: + return trp_asc_mark_nonsecure(x1); + default: + ERROR("Invalid SMC code to %s, FID %lu\n", __func__, fid); + } + return set_smc_args(SMC_UNK, 0, 0, 0, 0, 0, 0, 0); +} diff --git a/services/std_svc/rmmd/trp/trp_private.h b/services/std_svc/rmmd/trp/trp_private.h new file mode 100644 index 000000000..923139007 --- /dev/null +++ b/services/std_svc/rmmd/trp/trp_private.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TRP_PRIVATE_H +#define TRP_PRIVATE_H + +/* Definitions to help the assembler access the SMC/ERET args structure */ +#define TRP_ARGS_SIZE TRP_ARGS_END +#define TRP_ARG0 0x0 +#define TRP_ARG1 0x8 +#define TRP_ARG2 0x10 +#define TRP_ARG3 0x18 +#define TRP_ARG4 0x20 +#define TRP_ARG5 0x28 +#define TRP_ARG6 0x30 +#define TRP_ARG7 0x38 +#define TRP_ARGS_END 0x40 + +#ifndef __ASSEMBLER__ + +#include <stdint.h> + +/* Data structure to hold SMC arguments */ +typedef struct trp_args { + uint64_t regs[TRP_ARGS_END >> 3]; +} __aligned(CACHE_WRITEBACK_GRANULE) trp_args_t; + +#define write_trp_arg(args, offset, val) (((args)->regs[offset >> 3]) \ + = val) + +/* Definitions for RMI VERSION */ +#define RMI_ABI_VERSION_MAJOR U(0x0) +#define RMI_ABI_VERSION_MINOR U(0x0) +#define RMI_ABI_VERSION ((RMI_ABI_VERSION_MAJOR << 16) | \ + RMI_ABI_VERSION_MINOR) + +/* Helper to issue SMC calls to BL31 */ +uint64_t trp_smc(trp_args_t *); + +/* The main function to executed only by Primary CPU */ +void trp_main(void); + +/* Setup TRP. Executed only by Primary CPU */ +void trp_setup(void); + +#endif /* __ASSEMBLER__ */ +#endif /* TRP_PRIVATE_H */ diff --git a/services/std_svc/sdei/sdei_intr_mgmt.c b/services/std_svc/sdei/sdei_intr_mgmt.c index 5d176c209..87a1fb7dc 100644 --- a/services/std_svc/sdei/sdei_intr_mgmt.c +++ b/services/std_svc/sdei/sdei_intr_mgmt.c @@ -5,6 +5,8 @@ */ #include <assert.h> +#include <inttypes.h> +#include <stdint.h> #include <string.h> #include <arch_helpers.h> @@ -459,8 +461,8 @@ int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle, * Interrupts received while this PE was masked can't be * dispatched. */ - SDEI_LOG("interrupt %u on %llx while PE masked\n", map->intr, - mpidr); + SDEI_LOG("interrupt %u on %" PRIx64 " while PE masked\n", + map->intr, mpidr); if (is_event_shared(map)) sdei_map_lock(map); @@ -531,8 +533,8 @@ int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle, if (is_event_shared(map)) sdei_map_unlock(map); - SDEI_LOG("ACK %llx, ev:%d ss:%d spsr:%lx ELR:%lx\n", mpidr, map->ev_num, - sec_state, read_spsr_el3(), read_elr_el3()); + SDEI_LOG("ACK %" PRIx64 ", ev:0x%x ss:%d spsr:%lx ELR:%lx\n", + mpidr, map->ev_num, sec_state, read_spsr_el3(), read_elr_el3()); ctx = handle; @@ -568,7 +570,7 @@ int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle, * interrupt. */ if ((map->ev_num != SDEI_EVENT_0) && !is_map_bound(map)) { - ERROR("Invalid SDEI mapping: ev=%u\n", map->ev_num); + ERROR("Invalid SDEI mapping: ev=0x%x\n", map->ev_num); panic(); } plat_ic_end_of_interrupt(intr_raw); diff --git a/services/std_svc/sdei/sdei_main.c b/services/std_svc/sdei/sdei_main.c index 5371df1e3..44178eddd 100644 --- a/services/std_svc/sdei/sdei_main.c +++ b/services/std_svc/sdei/sdei_main.c @@ -6,7 +6,9 @@ #include <arch_helpers.h> #include <assert.h> +#include <inttypes.h> #include <stddef.h> +#include <stdint.h> #include <string.h> #include <bl31/bl31.h> @@ -359,8 +361,20 @@ static int64_t sdei_event_register(int ev_num, return SDEI_EINVAL; /* Private events always target the PE */ - if (is_event_private(map)) + if (is_event_private(map)) { + /* + * SDEI internally handles private events in the same manner + * as public events with routing mode=RM_PE, since the routing + * mode flag and affinity fields are not used when registering + * a private event, set them here. + */ flags = SDEI_REGF_RM_PE; + /* + * Kernel may pass 0 as mpidr, as we set flags to + * SDEI_REGF_RM_PE, so set mpidr also. + */ + mpidr = read_mpidr_el1(); + } se = get_event_entry(map); @@ -961,33 +975,33 @@ uint64_t sdei_smc_handler(uint32_t smc_fid, case SDEI_VERSION: SDEI_LOG("> VER\n"); ret = (int64_t) sdei_version(); - SDEI_LOG("< VER:%llx\n", ret); + SDEI_LOG("< VER:%" PRIx64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_REGISTER: x5 = SMC_GET_GP(ctx, CTX_GPREG_X5); - SDEI_LOG("> REG(n:%d e:%llx a:%llx f:%x m:%llx)\n", ev_num, + SDEI_LOG("> REG(n:%d e:%" PRIx64 " a:%" PRIx64 " f:%x m:%" PRIx64 "\n", ev_num, x2, x3, (int) x4, x5); ret = sdei_event_register(ev_num, x2, x3, x4, x5); - SDEI_LOG("< REG:%lld\n", ret); + SDEI_LOG("< REG:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_ENABLE: SDEI_LOG("> ENABLE(n:%d)\n", (int) x1); ret = sdei_event_enable(ev_num); - SDEI_LOG("< ENABLE:%lld\n", ret); + SDEI_LOG("< ENABLE:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_DISABLE: - SDEI_LOG("> DISABLE(n:%d)\n", ev_num); + SDEI_LOG("> DISABLE(n:0x%x)\n", ev_num); ret = sdei_event_disable(ev_num); - SDEI_LOG("< DISABLE:%lld\n", ret); + SDEI_LOG("< DISABLE:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_CONTEXT: SDEI_LOG("> CTX(p:%d):%lx\n", (int) x1, read_mpidr_el1()); ret = sdei_event_context(ctx, (unsigned int) x1); - SDEI_LOG("< CTX:%lld\n", ret); + SDEI_LOG("< CTX:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_COMPLETE_AND_RESUME: @@ -995,10 +1009,10 @@ uint64_t sdei_smc_handler(uint32_t smc_fid, /* Fallthrough */ case SDEI_EVENT_COMPLETE: - SDEI_LOG("> COMPLETE(r:%u sta/ep:%llx):%lx\n", - (unsigned int) resume, x1, read_mpidr_el1()); + SDEI_LOG("> COMPLETE(r:%u sta/ep:%" PRIx64 "):%lx\n", + (unsigned int) resume, x1, read_mpidr_el1()); ret = sdei_event_complete(resume, x1); - SDEI_LOG("< COMPLETE:%llx\n", ret); + SDEI_LOG("< COMPLETE:%" PRIx64 "\n", ret); /* * Set error code only if the call failed. If the call @@ -1013,21 +1027,21 @@ uint64_t sdei_smc_handler(uint32_t smc_fid, SMC_RET0(ctx); case SDEI_EVENT_STATUS: - SDEI_LOG("> STAT(n:%d)\n", ev_num); + SDEI_LOG("> STAT(n:0x%x)\n", ev_num); ret = sdei_event_status(ev_num); - SDEI_LOG("< STAT:%lld\n", ret); + SDEI_LOG("< STAT:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_GET_INFO: - SDEI_LOG("> INFO(n:%d, %d)\n", ev_num, (int) x2); + SDEI_LOG("> INFO(n:0x%x, %d)\n", ev_num, (int) x2); ret = sdei_event_get_info(ev_num, (int) x2); - SDEI_LOG("< INFO:%lld\n", ret); + SDEI_LOG("< INFO:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_UNREGISTER: - SDEI_LOG("> UNREG(n:%d)\n", ev_num); + SDEI_LOG("> UNREG(n:0x%x)\n", ev_num); ret = sdei_event_unregister(ev_num); - SDEI_LOG("< UNREG:%lld\n", ret); + SDEI_LOG("< UNREG:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_PE_UNMASK: @@ -1039,49 +1053,49 @@ uint64_t sdei_smc_handler(uint32_t smc_fid, case SDEI_PE_MASK: SDEI_LOG("> MASK:%lx\n", read_mpidr_el1()); ret = sdei_pe_mask(); - SDEI_LOG("< MASK:%lld\n", ret); + SDEI_LOG("< MASK:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_INTERRUPT_BIND: SDEI_LOG("> BIND(%d)\n", (int) x1); ret = sdei_interrupt_bind((unsigned int) x1); - SDEI_LOG("< BIND:%lld\n", ret); + SDEI_LOG("< BIND:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_INTERRUPT_RELEASE: - SDEI_LOG("> REL(%d)\n", ev_num); + SDEI_LOG("> REL(0x%x)\n", ev_num); ret = sdei_interrupt_release(ev_num); - SDEI_LOG("< REL:%lld\n", ret); + SDEI_LOG("< REL:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_SHARED_RESET: SDEI_LOG("> S_RESET():%lx\n", read_mpidr_el1()); ret = sdei_shared_reset(); - SDEI_LOG("< S_RESET:%lld\n", ret); + SDEI_LOG("< S_RESET:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_PRIVATE_RESET: SDEI_LOG("> P_RESET():%lx\n", read_mpidr_el1()); ret = sdei_private_reset(); - SDEI_LOG("< P_RESET:%lld\n", ret); + SDEI_LOG("< P_RESET:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_ROUTING_SET: - SDEI_LOG("> ROUTE_SET(n:%d f:%llx aff:%llx)\n", ev_num, x2, x3); + SDEI_LOG("> ROUTE_SET(n:%d f:%" PRIx64 " aff:%" PRIx64 ")\n", ev_num, x2, x3); ret = sdei_event_routing_set(ev_num, x2, x3); - SDEI_LOG("< ROUTE_SET:%lld\n", ret); + SDEI_LOG("< ROUTE_SET:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_FEATURES: - SDEI_LOG("> FTRS(f:%llx)\n", x1); + SDEI_LOG("> FTRS(f:%" PRIx64 ")\n", x1); ret = (int64_t) sdei_features((unsigned int) x1); - SDEI_LOG("< FTRS:%llx\n", ret); + SDEI_LOG("< FTRS:%" PRIx64 "\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_SIGNAL: - SDEI_LOG("> SIGNAL(e:%d t:%llx)\n", ev_num, x2); + SDEI_LOG("> SIGNAL(e:%d t:%" PRIx64 ")\n", ev_num, x2); ret = sdei_signal(ev_num, x2); - SDEI_LOG("< SIGNAL:%lld\n", ret); + SDEI_LOG("< SIGNAL:%" PRId64 "\n", ret); SMC_RET1(ctx, ret); default: diff --git a/services/std_svc/spm_mm/spm_mm.mk b/services/std_svc/spm_mm/spm_mm.mk index 656488b8e..a87bdd878 100644 --- a/services/std_svc/spm_mm/spm_mm.mk +++ b/services/std_svc/spm_mm/spm_mm.mk @@ -10,6 +10,12 @@ endif ifneq (${ARCH},aarch64) $(error "Error: SPM_MM is only supported on aarch64.") endif +ifeq (${ENABLE_SVE_FOR_NS},1) + $(error "Error: SPM_MM is not compatible with ENABLE_SVE_FOR_NS") +endif +ifeq (${ENABLE_SME_FOR_NS},1) + $(error "Error: SPM_MM is not compatible with ENABLE_SME_FOR_NS") +endif SPM_SOURCES := $(addprefix services/std_svc/spm_mm/, \ ${ARCH}/spm_mm_helpers.S \ diff --git a/services/std_svc/spmd/spmd.mk b/services/std_svc/spmd/spmd.mk index 73f7c85dd..8efbdc868 100644 --- a/services/std_svc/spmd/spmd.mk +++ b/services/std_svc/spmd/spmd.mk @@ -1,11 +1,15 @@ # -# Copyright (c) 2020, ARM Limited and Contributors. All rights reserved. +# Copyright (c) 2021, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ifneq (${ARCH},aarch64) - $(error "Error: SPMD is only supported on aarch64.") + $(error "Error: SPMD is only supported on aarch64.") +endif + +ifeq (${ENABLE_SME_FOR_NS},1) + $(error "Error: SPMD is not compatible with ENABLE_SME_FOR_NS") endif SPMD_SOURCES += $(addprefix services/std_svc/spmd/, \ diff --git a/services/std_svc/spmd/spmd_main.c b/services/std_svc/spmd/spmd_main.c index dda127fd4..f5de54966 100644 --- a/services/std_svc/spmd/spmd_main.c +++ b/services/std_svc/spmd/spmd_main.c @@ -6,11 +6,14 @@ #include <assert.h> #include <errno.h> +#include <inttypes.h> +#include <stdint.h> #include <string.h> #include <arch_helpers.h> #include <arch/aarch64/arch_features.h> #include <bl31/bl31.h> +#include <bl31/interrupt_mgmt.h> #include <common/debug.h> #include <common/runtime_svc.h> #include <lib/el3_runtime/context_mgmt.h> @@ -49,7 +52,7 @@ spmd_spm_core_context_t *spmd_get_context_by_mpidr(uint64_t mpidr) int core_idx = plat_core_pos_by_mpidr(mpidr); if (core_idx < 0) { - ERROR("Invalid mpidr: %llx, returned ID: %d\n", mpidr, core_idx); + ERROR("Invalid mpidr: %" PRIx64 ", returned ID: %d\n", mpidr, core_idx); panic(); } @@ -65,14 +68,6 @@ spmd_spm_core_context_t *spmd_get_context(void) } /******************************************************************************* - * SPM Core entry point information get helper. - ******************************************************************************/ -entry_point_info_t *spmd_spmc_ep_info_get(void) -{ - return spmc_ep_info; -} - -/******************************************************************************* * SPM Core ID getter. ******************************************************************************/ uint16_t spmd_spmc_id_get(void) @@ -156,22 +151,15 @@ static int32_t spmd_init(void) { spmd_spm_core_context_t *ctx = spmd_get_context(); uint64_t rc; - unsigned int linear_id = plat_my_core_pos(); - unsigned int core_id; VERBOSE("SPM Core init start.\n"); - ctx->state = SPMC_STATE_ON_PENDING; - /* Set the SPMC context state on other CPUs to OFF */ - for (core_id = 0U; core_id < PLATFORM_CORE_COUNT; core_id++) { - if (core_id != linear_id) { - spm_core_context[core_id].state = SPMC_STATE_OFF; - } - } + /* Primary boot core enters the SPMC for initialization. */ + ctx->state = SPMC_STATE_ON_PENDING; rc = spmd_spm_core_sync_entry(ctx); if (rc != 0ULL) { - ERROR("SPMC initialisation failed 0x%llx\n", rc); + ERROR("SPMC initialisation failed 0x%" PRIx64 "\n", rc); return 0; } @@ -183,12 +171,69 @@ static int32_t spmd_init(void) } /******************************************************************************* + * spmd_secure_interrupt_handler + * Enter the SPMC for further handling of the secure interrupt by the SPMC + * itself or a Secure Partition. + ******************************************************************************/ +static uint64_t spmd_secure_interrupt_handler(uint32_t id, + uint32_t flags, + void *handle, + void *cookie) +{ + spmd_spm_core_context_t *ctx = spmd_get_context(); + gp_regs_t *gpregs = get_gpregs_ctx(&ctx->cpu_ctx); + unsigned int linear_id = plat_my_core_pos(); + int64_t rc; + + /* Sanity check the security state when the exception was generated */ + assert(get_interrupt_src_ss(flags) == NON_SECURE); + + /* Sanity check the pointer to this cpu's context */ + assert(handle == cm_get_context(NON_SECURE)); + + /* Save the non-secure context before entering SPMC */ + cm_el1_sysregs_context_save(NON_SECURE); +#if SPMD_SPM_AT_SEL2 + cm_el2_sysregs_context_save(NON_SECURE); +#endif + + /* Convey the event to the SPMC through the FFA_INTERRUPT interface. */ + write_ctx_reg(gpregs, CTX_GPREG_X0, FFA_INTERRUPT); + write_ctx_reg(gpregs, CTX_GPREG_X1, 0); + write_ctx_reg(gpregs, CTX_GPREG_X2, 0); + write_ctx_reg(gpregs, CTX_GPREG_X3, 0); + write_ctx_reg(gpregs, CTX_GPREG_X4, 0); + write_ctx_reg(gpregs, CTX_GPREG_X5, 0); + write_ctx_reg(gpregs, CTX_GPREG_X6, 0); + write_ctx_reg(gpregs, CTX_GPREG_X7, 0); + + /* Mark current core as handling a secure interrupt. */ + ctx->secure_interrupt_ongoing = true; + + rc = spmd_spm_core_sync_entry(ctx); + if (rc != 0ULL) { + ERROR("%s failed (%" PRId64 ") on CPU%u\n", __func__, rc, linear_id); + } + + ctx->secure_interrupt_ongoing = false; + + cm_el1_sysregs_context_restore(NON_SECURE); +#if SPMD_SPM_AT_SEL2 + cm_el2_sysregs_context_restore(NON_SECURE); +#endif + cm_set_next_eret_context(NON_SECURE); + + SMC_RET0(&ctx->cpu_ctx); +} + +/******************************************************************************* * Loads SPMC manifest and inits SPMC. ******************************************************************************/ static int spmd_spmc_init(void *pm_addr) { - spmd_spm_core_context_t *spm_ctx = spmd_get_context(); - uint32_t ep_attr; + cpu_context_t *cpu_ctx; + unsigned int core_id; + uint32_t ep_attr, flags; int rc; /* Load the SPM Core manifest */ @@ -280,13 +325,21 @@ static int spmd_spmc_init(void *pm_addr) DISABLE_ALL_EXCEPTIONS); } - /* Initialise SPM Core context with this entry point information */ - cm_setup_context(&spm_ctx->cpu_ctx, spmc_ep_info); + /* Set an initial SPMC context state for all cores. */ + for (core_id = 0U; core_id < PLATFORM_CORE_COUNT; core_id++) { + spm_core_context[core_id].state = SPMC_STATE_OFF; - /* Reuse PSCI affinity states to mark this SPMC context as off */ - spm_ctx->state = AFF_STATE_OFF; + /* Setup an initial cpu context for the SPMC. */ + cpu_ctx = &spm_core_context[core_id].cpu_ctx; + cm_setup_context(cpu_ctx, spmc_ep_info); - INFO("SPM Core setup done.\n"); + /* + * Pass the core linear ID to the SPMC through x4. + * (TF-A implementation defined behavior helping + * a legacy TOS migration to adopt FF-A). + */ + write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4, core_id); + } /* Register power management hooks with PSCI */ psci_register_spd_pm_hook(&spmd_pm); @@ -294,6 +347,21 @@ static int spmd_spmc_init(void *pm_addr) /* Register init function for deferred init. */ bl31_register_bl32_init(&spmd_init); + INFO("SPM Core setup done.\n"); + + /* + * Register an interrupt handler routing secure interrupts to SPMD + * while the NWd is running. + */ + flags = 0; + set_interrupt_rm_flag(flags, NON_SECURE); + rc = register_interrupt_type_handler(INTR_TYPE_S_EL1, + spmd_secure_interrupt_handler, + flags); + if (rc != 0) { + panic(); + } + return 0; } @@ -440,12 +508,12 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, /* Determine which security state this SMC originated from */ secure_origin = is_caller_secure(flags); - VERBOSE("SPM(%u): 0x%x 0x%llx 0x%llx 0x%llx 0x%llx " - "0x%llx 0x%llx 0x%llx\n", - linear_id, smc_fid, x1, x2, x3, x4, - SMC_GET_GP(handle, CTX_GPREG_X5), - SMC_GET_GP(handle, CTX_GPREG_X6), - SMC_GET_GP(handle, CTX_GPREG_X7)); + VERBOSE("SPM(%u): 0x%x 0x%" PRIx64 " 0x%" PRIx64 " 0x%" PRIx64 " 0x%" PRIx64 + " 0x%" PRIx64 " 0x%" PRIx64 " 0x%" PRIx64 "\n", + linear_id, smc_fid, x1, x2, x3, x4, + SMC_GET_GP(handle, CTX_GPREG_X5), + SMC_GET_GP(handle, CTX_GPREG_X6), + SMC_GET_GP(handle, CTX_GPREG_X7)); switch (smc_fid) { case FFA_ERROR: @@ -493,15 +561,6 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, * forward to SPM Core which will handle it if implemented. */ - /* - * Check if x1 holds a valid FFA fid. This is an - * optimization. - */ - if (!is_ffa_fid(x1)) { - return spmd_ffa_error_return(handle, - FFA_ERROR_NOT_SUPPORTED); - } - /* Forward SMC from Normal world to the SPM Core */ if (!secure_origin) { return spmd_smc_forward(smc_fid, secure_origin, @@ -607,7 +666,7 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, case FFA_MSG_SEND_DIRECT_RESP_SMC32: if (secure_origin && spmd_is_spmc_message(x1)) { - spmd_spm_core_sync_exit(0); + spmd_spm_core_sync_exit(0ULL); } else { /* Forward direct message to the other world */ return spmd_smc_forward(smc_fid, secure_origin, @@ -620,9 +679,19 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, case FFA_RXTX_MAP_SMC64: case FFA_RXTX_UNMAP: case FFA_PARTITION_INFO_GET: +#if MAKE_FFA_VERSION(1, 1) <= FFA_VERSION_COMPILED + case FFA_NOTIFICATION_BITMAP_CREATE: + case FFA_NOTIFICATION_BITMAP_DESTROY: + case FFA_NOTIFICATION_BIND: + case FFA_NOTIFICATION_UNBIND: + case FFA_NOTIFICATION_SET: + case FFA_NOTIFICATION_GET: + case FFA_NOTIFICATION_INFO_GET: + case FFA_NOTIFICATION_INFO_GET_SMC64: +#endif /* - * Should not be allowed to forward FFA_PARTITION_INFO_GET - * from Secure world to Normal world + * Above calls should not be forwarded from Secure world to + * Normal world. * * Fall through to forward the call to the other world */ @@ -669,7 +738,7 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, * SPM Core initialised successfully. */ if (secure_origin && (ctx->state == SPMC_STATE_ON_PENDING)) { - spmd_spm_core_sync_exit(0); + spmd_spm_core_sync_exit(0ULL); } /* Fall through to forward the call to the other world */ @@ -685,6 +754,14 @@ uint64_t spmd_smc_handler(uint32_t smc_fid, x1, x2, x3, x4, handle); break; /* not reached */ + case FFA_NORMAL_WORLD_RESUME: + if (secure_origin && ctx->secure_interrupt_ongoing) { + spmd_spm_core_sync_exit(0ULL); + } else { + return spmd_ffa_error_return(handle, FFA_ERROR_DENIED); + } + break; /* Not reached */ + default: WARN("SPM: Unsupported call 0x%08x\n", smc_fid); return spmd_ffa_error_return(handle, FFA_ERROR_NOT_SUPPORTED); diff --git a/services/std_svc/spmd/spmd_pm.c b/services/std_svc/spmd/spmd_pm.c index 074609c89..6ebafcaa7 100644 --- a/services/std_svc/spmd/spmd_pm.c +++ b/services/std_svc/spmd/spmd_pm.c @@ -6,6 +6,9 @@ #include <assert.h> #include <errno.h> +#include <inttypes.h> +#include <stdint.h> + #include <lib/el3_runtime/context_mgmt.h> #include <lib/spinlock.h> #include "spmd_private.h" @@ -75,14 +78,14 @@ out: ******************************************************************************/ static void spmd_cpu_on_finish_handler(u_register_t unused) { - entry_point_info_t *spmc_ep_info = spmd_spmc_ep_info_get(); spmd_spm_core_context_t *ctx = spmd_get_context(); unsigned int linear_id = plat_my_core_pos(); + el3_state_t *el3_state; + uintptr_t entry_point; uint64_t rc; assert(ctx != NULL); assert(ctx->state != SPMC_STATE_ON); - assert(spmc_ep_info != NULL); spin_lock(&g_spmd_pm.lock); @@ -92,19 +95,25 @@ static void spmd_cpu_on_finish_handler(u_register_t unused) * primary core address for booting secondary cores. */ if (g_spmd_pm.secondary_ep_locked == true) { - spmc_ep_info->pc = g_spmd_pm.secondary_ep; + /* + * The CPU context has already been initialized at boot time + * (in spmd_spmc_init by a call to cm_setup_context). Adjust + * below the target core entry point based on the address + * passed to by FFA_SECONDARY_EP_REGISTER. + */ + entry_point = g_spmd_pm.secondary_ep; + el3_state = get_el3state_ctx(&ctx->cpu_ctx); + write_ctx_reg(el3_state, CTX_ELR_EL3, entry_point); } spin_unlock(&g_spmd_pm.lock); - cm_setup_context(&ctx->cpu_ctx, spmc_ep_info); - - /* Mark CPU as initiating ON operation */ + /* Mark CPU as initiating ON operation. */ ctx->state = SPMC_STATE_ON_PENDING; rc = spmd_spm_core_sync_entry(ctx); if (rc != 0ULL) { - ERROR("%s failed (%llu) on CPU%u\n", __func__, rc, + ERROR("%s failed (%" PRIu64 ") on CPU%u\n", __func__, rc, linear_id); ctx->state = SPMC_STATE_OFF; return; @@ -132,7 +141,7 @@ static int32_t spmd_cpu_off_handler(u_register_t unused) rc = spmd_spm_core_sync_entry(ctx); if (rc != 0ULL) { - ERROR("%s failed (%llu) on CPU%u\n", __func__, rc, linear_id); + ERROR("%s failed (%" PRIu64 ") on CPU%u\n", __func__, rc, linear_id); } /* Expect a direct message response from the SPMC. */ diff --git a/services/std_svc/spmd/spmd_private.h b/services/std_svc/spmd/spmd_private.h index 6d51a58e0..1fe506524 100644 --- a/services/std_svc/spmd/spmd_private.h +++ b/services/std_svc/spmd/spmd_private.h @@ -50,6 +50,7 @@ typedef struct spmd_spm_core_context { uint64_t c_rt_ctx; cpu_context_t cpu_ctx; spmc_state_t state; + bool secure_interrupt_ongoing; } spmd_spm_core_context_t; /* diff --git a/services/std_svc/std_svc_setup.c b/services/std_svc/std_svc_setup.c index 1917d0a14..39db42913 100644 --- a/services/std_svc/std_svc_setup.c +++ b/services/std_svc/std_svc_setup.c @@ -13,7 +13,9 @@ #include <lib/pmf/pmf.h> #include <lib/psci/psci.h> #include <lib/runtime_instr.h> +#include <services/gtsi_svc.h> #include <services/pci_svc.h> +#include <services/rmmd_svc.h> #include <services/sdei.h> #include <services/spm_mm_svc.h> #include <services/spmd_svc.h> @@ -158,6 +160,16 @@ static uintptr_t std_svc_smc_handler(uint32_t smc_fid, flags); } #endif +#if ENABLE_RME + /* + * Granule transition service interface functions (GTSI) are allocated + * from the Std service range. Call the RMM dispatcher to handle calls. + */ + if (is_gtsi_fid(smc_fid)) { + return rmmd_gtsi_handler(smc_fid, x1, x2, x3, x4, cookie, + handle, flags); + } +#endif #if SMC_PCI_SUPPORT if (is_pci_fid(smc_fid)) { |