aboutsummaryrefslogtreecommitdiff
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/arm_arch_svc/arm_arch_svc_setup.c26
-rw-r--r--services/spd/trusty/trusty.c10
-rw-r--r--services/std_svc/rmmd/aarch64/rmmd_helpers.S73
-rw-r--r--services/std_svc/rmmd/rmmd.mk18
-rw-r--r--services/std_svc/rmmd/rmmd_initial_context.h33
-rw-r--r--services/std_svc/rmmd/rmmd_main.c347
-rw-r--r--services/std_svc/rmmd/rmmd_private.h64
-rw-r--r--services/std_svc/rmmd/trp/linker.lds71
-rw-r--r--services/std_svc/rmmd/trp/trp.mk20
-rw-r--r--services/std_svc/rmmd/trp/trp_entry.S74
-rw-r--r--services/std_svc/rmmd/trp/trp_main.c136
-rw-r--r--services/std_svc/rmmd/trp/trp_private.h50
-rw-r--r--services/std_svc/sdei/sdei_intr_mgmt.c12
-rw-r--r--services/std_svc/sdei/sdei_main.c72
-rw-r--r--services/std_svc/spm_mm/spm_mm.mk6
-rw-r--r--services/std_svc/spmd/spmd.mk8
-rw-r--r--services/std_svc/spmd/spmd_main.c167
-rw-r--r--services/std_svc/spmd/spmd_pm.c25
-rw-r--r--services/std_svc/spmd/spmd_private.h1
-rw-r--r--services/std_svc/std_svc_setup.c12
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)) {