2 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
7 #include <arch_helpers.h>
11 #include <bl31/bl31.h>
13 #include <common/debug.h>
14 #include <common/runtime_svc.h>
15 #include <lib/el3_runtime/context_mgmt.h>
16 #include <lib/smccc.h>
17 #include <lib/spinlock.h>
18 #include <lib/utils.h>
19 #include <lib/xlat_tables/xlat_tables_v2.h>
20 #include <plat/common/platform.h>
21 #include <services/mm_svc.h>
22 #include <services/secure_partition.h>
23 #include <services/spm_svc.h>
24 #include <smccc_helpers.h>
26 #include "spm_private.h"
28 /*******************************************************************************
29 * Secure Partition context information.
30 ******************************************************************************/
31 static sp_context_t sp_ctx
;
33 /*******************************************************************************
34 * Set state of a Secure Partition context.
35 ******************************************************************************/
36 void sp_state_set(sp_context_t
*sp_ptr
, sp_state_t state
)
38 spin_lock(&(sp_ptr
->state_lock
));
39 sp_ptr
->state
= state
;
40 spin_unlock(&(sp_ptr
->state_lock
));
43 /*******************************************************************************
44 * Wait until the state of a Secure Partition is the specified one and change it
45 * to the desired state.
46 ******************************************************************************/
47 void sp_state_wait_switch(sp_context_t
*sp_ptr
, sp_state_t from
, sp_state_t to
)
51 while (success
== 0) {
52 spin_lock(&(sp_ptr
->state_lock
));
54 if (sp_ptr
->state
== from
) {
60 spin_unlock(&(sp_ptr
->state_lock
));
64 /*******************************************************************************
65 * Check if the state of a Secure Partition is the specified one and, if so,
66 * change it to the desired state. Returns 0 on success, -1 on error.
67 ******************************************************************************/
68 int sp_state_try_switch(sp_context_t
*sp_ptr
, sp_state_t from
, sp_state_t to
)
72 spin_lock(&(sp_ptr
->state_lock
));
74 if (sp_ptr
->state
== from
) {
80 spin_unlock(&(sp_ptr
->state_lock
));
85 /*******************************************************************************
86 * This function takes an SP context pointer and performs a synchronous entry
88 ******************************************************************************/
89 static uint64_t spm_sp_synchronous_entry(sp_context_t
*sp_ctx
)
93 assert(sp_ctx
!= NULL
);
95 /* Assign the context of the SP to this CPU */
96 cm_set_context(&(sp_ctx
->cpu_ctx
), SECURE
);
98 /* Restore the context assigned above */
99 cm_el1_sysregs_context_restore(SECURE
);
100 cm_set_next_eret_context(SECURE
);
102 /* Invalidate TLBs at EL1. */
106 /* Enter Secure Partition */
107 rc
= spm_secure_partition_enter(&sp_ctx
->c_rt_ctx
);
109 /* Save secure state */
110 cm_el1_sysregs_context_save(SECURE
);
115 /*******************************************************************************
116 * This function returns to the place where spm_sp_synchronous_entry() was
118 ******************************************************************************/
119 __dead2
static void spm_sp_synchronous_exit(uint64_t rc
)
121 sp_context_t
*ctx
= &sp_ctx
;
124 * The SPM must have initiated the original request through a
125 * synchronous entry into the secure partition. Jump back to the
126 * original C runtime context with the value of rc in x0;
128 spm_secure_partition_exit(ctx
->c_rt_ctx
, rc
);
133 /*******************************************************************************
134 * Jump to each Secure Partition for the first time.
135 ******************************************************************************/
136 static int32_t spm_init(void)
141 INFO("Secure Partition init...\n");
145 ctx
->state
= SP_STATE_RESET
;
147 rc
= spm_sp_synchronous_entry(ctx
);
150 ctx
->state
= SP_STATE_IDLE
;
152 INFO("Secure Partition initialized.\n");
157 /*******************************************************************************
158 * Initialize contexts of all Secure Partitions.
159 ******************************************************************************/
160 int32_t spm_setup(void)
164 /* Disable MMU at EL1 (initialized by BL2) */
165 disable_mmu_icache_el1();
167 /* Initialize context of the SP */
168 INFO("Secure Partition context setup start...\n");
172 /* Assign translation tables context. */
173 ctx
->xlat_ctx_handle
= spm_get_sp_xlat_context();
177 /* Register init function for deferred init. */
178 bl31_register_bl32_init(&spm_init
);
180 INFO("Secure Partition setup done.\n");
185 /*******************************************************************************
186 * Function to perform a call to a Secure Partition.
187 ******************************************************************************/
188 uint64_t spm_sp_call(uint32_t smc_fid
, uint64_t x1
, uint64_t x2
, uint64_t x3
)
191 sp_context_t
*sp_ptr
= &sp_ctx
;
193 /* Wait until the Secure Partition is idle and set it to busy. */
194 sp_state_wait_switch(sp_ptr
, SP_STATE_IDLE
, SP_STATE_BUSY
);
196 /* Set values for registers on SP entry */
197 cpu_context_t
*cpu_ctx
= &(sp_ptr
->cpu_ctx
);
199 write_ctx_reg(get_gpregs_ctx(cpu_ctx
), CTX_GPREG_X0
, smc_fid
);
200 write_ctx_reg(get_gpregs_ctx(cpu_ctx
), CTX_GPREG_X1
, x1
);
201 write_ctx_reg(get_gpregs_ctx(cpu_ctx
), CTX_GPREG_X2
, x2
);
202 write_ctx_reg(get_gpregs_ctx(cpu_ctx
), CTX_GPREG_X3
, x3
);
204 /* Jump to the Secure Partition. */
205 rc
= spm_sp_synchronous_entry(sp_ptr
);
207 /* Flag Secure Partition as idle. */
208 assert(sp_ptr
->state
== SP_STATE_BUSY
);
209 sp_state_set(sp_ptr
, SP_STATE_IDLE
);
214 /*******************************************************************************
215 * MM_COMMUNICATE handler
216 ******************************************************************************/
217 static uint64_t mm_communicate(uint32_t smc_fid
, uint64_t mm_cookie
,
218 uint64_t comm_buffer_address
,
219 uint64_t comm_size_address
, void *handle
)
223 /* Cookie. Reserved for future use. It must be zero. */
224 if (mm_cookie
!= 0U) {
225 ERROR("MM_COMMUNICATE: cookie is not zero\n");
226 SMC_RET1(handle
, SPM_INVALID_PARAMETER
);
229 if (comm_buffer_address
== 0U) {
230 ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
231 SMC_RET1(handle
, SPM_INVALID_PARAMETER
);
234 if (comm_size_address
!= 0U) {
235 VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n");
239 * The current secure partition design mandates
240 * - at any point, only a single core can be
241 * executing in the secure partiton.
242 * - a core cannot be preempted by an interrupt
243 * while executing in secure partition.
244 * Raise the running priority of the core to the
245 * interrupt level configured for secure partition
246 * so as to block any interrupt from preempting this
249 ehf_activate_priority(PLAT_SP_PRI
);
251 /* Save the Normal world context */
252 cm_el1_sysregs_context_save(NON_SECURE
);
254 rc
= spm_sp_call(smc_fid
, comm_buffer_address
, comm_size_address
,
257 /* Restore non-secure state */
258 cm_el1_sysregs_context_restore(NON_SECURE
);
259 cm_set_next_eret_context(NON_SECURE
);
262 * Exited from secure partition. This core can take
265 ehf_deactivate_priority(PLAT_SP_PRI
);
267 SMC_RET1(handle
, rc
);
270 /*******************************************************************************
271 * Secure Partition Manager SMC handler.
272 ******************************************************************************/
273 uint64_t spm_smc_handler(uint32_t smc_fid
,
284 /* Determine which security state this SMC originated from */
285 ns
= is_caller_non_secure(flags
);
287 if (ns
== SMC_FROM_SECURE
) {
289 /* Handle SMCs from Secure world. */
291 assert(handle
== cm_get_context(SECURE
));
293 /* Make next ERET jump to S-EL0 instead of S-EL1. */
294 cm_set_elr_spsr_el3(SECURE
, read_elr_el1(), read_spsr_el1());
298 case SPM_VERSION_AARCH32
:
299 SMC_RET1(handle
, SPM_VERSION_COMPILED
);
301 case SP_EVENT_COMPLETE_AARCH64
:
302 spm_sp_synchronous_exit(x1
);
304 case SP_MEMORY_ATTRIBUTES_GET_AARCH64
:
305 INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
307 if (sp_ctx
.state
!= SP_STATE_RESET
) {
308 WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
309 SMC_RET1(handle
, SPM_NOT_SUPPORTED
);
312 spm_memory_attributes_get_smc_handler(
315 case SP_MEMORY_ATTRIBUTES_SET_AARCH64
:
316 INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
318 if (sp_ctx
.state
!= SP_STATE_RESET
) {
319 WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
320 SMC_RET1(handle
, SPM_NOT_SUPPORTED
);
323 spm_memory_attributes_set_smc_handler(
324 &sp_ctx
, x1
, x2
, x3
));
330 /* Handle SMCs from Non-secure world. */
332 assert(handle
== cm_get_context(NON_SECURE
));
336 case MM_VERSION_AARCH32
:
337 SMC_RET1(handle
, MM_VERSION_COMPILED
);
339 case MM_COMMUNICATE_AARCH32
:
340 case MM_COMMUNICATE_AARCH64
:
341 return mm_communicate(smc_fid
, x1
, x2
, x3
, handle
);
343 case SP_MEMORY_ATTRIBUTES_GET_AARCH64
:
344 case SP_MEMORY_ATTRIBUTES_SET_AARCH64
:
345 /* SMC interfaces reserved for secure callers. */
346 SMC_RET1(handle
, SPM_NOT_SUPPORTED
);
353 SMC_RET1(handle
, SMC_UNK
);