2 * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
4 * SPDX-License-Identifier: BSD-3-Clause
11 #include <arch_helpers.h>
12 #include <bl31/bl31.h>
14 #include <bl31/interrupt_mgmt.h>
15 #include <common/debug.h>
16 #include <common/runtime_svc.h>
17 #include <lib/el3_runtime/context_mgmt.h>
18 #include <lib/smccc.h>
19 #include <lib/spinlock.h>
20 #include <lib/utils.h>
21 #include <lib/xlat_tables/xlat_tables_v2.h>
22 #include <plat/common/platform.h>
23 #include <services/spm_svc.h>
24 #include <services/sprt_svc.h>
25 #include <smccc_helpers.h>
27 #include "spm_private.h"
29 /*******************************************************************************
30 * Secure Partition context information.
31 ******************************************************************************/
32 sp_context_t sp_ctx_array
[PLAT_SPM_MAX_PARTITIONS
];
34 /* Last Secure Partition last used by the CPU */
35 sp_context_t
*cpu_sp_ctx
[PLATFORM_CORE_COUNT
];
37 void spm_cpu_set_sp_ctx(unsigned int linear_id
, sp_context_t
*sp_ctx
)
39 assert(linear_id
< PLATFORM_CORE_COUNT
);
41 cpu_sp_ctx
[linear_id
] = sp_ctx
;
44 sp_context_t
*spm_cpu_get_sp_ctx(unsigned int linear_id
)
46 assert(linear_id
< PLATFORM_CORE_COUNT
);
48 return cpu_sp_ctx
[linear_id
];
51 /*******************************************************************************
52 * Functions to keep track of how many requests a Secure Partition has received
53 * and hasn't finished.
54 ******************************************************************************/
55 void spm_sp_request_increase(sp_context_t
*sp_ctx
)
57 spin_lock(&(sp_ctx
->request_count_lock
));
58 sp_ctx
->request_count
++;
59 spin_unlock(&(sp_ctx
->request_count_lock
));
62 void spm_sp_request_decrease(sp_context_t
*sp_ctx
)
64 spin_lock(&(sp_ctx
->request_count_lock
));
65 sp_ctx
->request_count
--;
66 spin_unlock(&(sp_ctx
->request_count_lock
));
69 /* Returns 0 if it was originally 0, -1 otherwise. */
70 int spm_sp_request_increase_if_zero(sp_context_t
*sp_ctx
)
74 spin_lock(&(sp_ctx
->request_count_lock
));
75 if (sp_ctx
->request_count
== 0U) {
76 sp_ctx
->request_count
++;
79 spin_unlock(&(sp_ctx
->request_count_lock
));
84 /*******************************************************************************
85 * This function returns a pointer to the context of the Secure Partition that
86 * handles the service specified by an UUID. It returns NULL if the UUID wasn't
88 ******************************************************************************/
89 sp_context_t
*spm_sp_get_by_uuid(const uint32_t (*svc_uuid
)[4])
93 for (i
= 0U; i
< PLAT_SPM_MAX_PARTITIONS
; i
++) {
95 sp_context_t
*sp_ctx
= &sp_ctx_array
[i
];
97 if (sp_ctx
->is_present
== 0) {
101 struct sp_rd_sect_service
*rdsvc
;
103 for (rdsvc
= sp_ctx
->rd
.service
; rdsvc
!= NULL
;
104 rdsvc
= rdsvc
->next
) {
105 uint32_t *rd_uuid
= (uint32_t *)(rdsvc
->uuid
);
107 if (memcmp(rd_uuid
, svc_uuid
, sizeof(rd_uuid
)) == 0) {
116 /*******************************************************************************
117 * Set state of a Secure Partition context.
118 ******************************************************************************/
119 void sp_state_set(sp_context_t
*sp_ptr
, sp_state_t state
)
121 spin_lock(&(sp_ptr
->state_lock
));
122 sp_ptr
->state
= state
;
123 spin_unlock(&(sp_ptr
->state_lock
));
126 /*******************************************************************************
127 * Wait until the state of a Secure Partition is the specified one and change it
128 * to the desired state.
129 ******************************************************************************/
130 void sp_state_wait_switch(sp_context_t
*sp_ptr
, sp_state_t from
, sp_state_t to
)
134 while (success
== 0) {
135 spin_lock(&(sp_ptr
->state_lock
));
137 if (sp_ptr
->state
== from
) {
143 spin_unlock(&(sp_ptr
->state_lock
));
147 /*******************************************************************************
148 * Check if the state of a Secure Partition is the specified one and, if so,
149 * change it to the desired state. Returns 0 on success, -1 on error.
150 ******************************************************************************/
151 int sp_state_try_switch(sp_context_t
*sp_ptr
, sp_state_t from
, sp_state_t to
)
155 spin_lock(&(sp_ptr
->state_lock
));
157 if (sp_ptr
->state
== from
) {
163 spin_unlock(&(sp_ptr
->state_lock
));
168 /*******************************************************************************
169 * This function takes an SP context pointer and performs a synchronous entry
171 ******************************************************************************/
172 uint64_t spm_sp_synchronous_entry(sp_context_t
*sp_ctx
, int can_preempt
)
175 unsigned int linear_id
= plat_my_core_pos();
177 assert(sp_ctx
!= NULL
);
179 /* Assign the context of the SP to this CPU */
180 spm_cpu_set_sp_ctx(linear_id
, sp_ctx
);
181 cm_set_context(&(sp_ctx
->cpu_ctx
), SECURE
);
183 /* Restore the context assigned above */
184 cm_el1_sysregs_context_restore(SECURE
);
185 cm_set_next_eret_context(SECURE
);
187 /* Invalidate TLBs at EL1. */
191 if (can_preempt
== 1) {
192 enable_intr_rm_local(INTR_TYPE_NS
, SECURE
);
194 disable_intr_rm_local(INTR_TYPE_NS
, SECURE
);
197 /* Enter Secure Partition */
198 rc
= spm_secure_partition_enter(&sp_ctx
->c_rt_ctx
);
200 /* Save secure state */
201 cm_el1_sysregs_context_save(SECURE
);
206 /*******************************************************************************
207 * This function returns to the place where spm_sp_synchronous_entry() was
209 ******************************************************************************/
210 __dead2
void spm_sp_synchronous_exit(uint64_t rc
)
212 /* Get context of the SP in use by this CPU. */
213 unsigned int linear_id
= plat_my_core_pos();
214 sp_context_t
*ctx
= spm_cpu_get_sp_ctx(linear_id
);
217 * The SPM must have initiated the original request through a
218 * synchronous entry into the secure partition. Jump back to the
219 * original C runtime context with the value of rc in x0;
221 spm_secure_partition_exit(ctx
->c_rt_ctx
, rc
);
226 /*******************************************************************************
227 * This function is the handler registered for Non secure interrupts by the SPM.
228 * It validates the interrupt and upon success arranges entry into the normal
229 * world for handling the interrupt.
230 ******************************************************************************/
231 static uint64_t spm_ns_interrupt_handler(uint32_t id
, uint32_t flags
,
232 void *handle
, void *cookie
)
234 /* Check the security state when the exception was generated */
235 assert(get_interrupt_src_ss(flags
) == SECURE
);
237 spm_sp_synchronous_exit(SPM_SECURE_PARTITION_PREEMPTED
);
240 /*******************************************************************************
241 * Jump to each Secure Partition for the first time.
242 ******************************************************************************/
243 static int32_t spm_init(void)
248 for (unsigned int i
= 0U; i
< PLAT_SPM_MAX_PARTITIONS
; i
++) {
250 ctx
= &sp_ctx_array
[i
];
252 if (ctx
->is_present
== 0) {
256 INFO("Secure Partition %u init...\n", i
);
258 ctx
->state
= SP_STATE_RESET
;
260 rc
= spm_sp_synchronous_entry(ctx
, 0);
261 if (rc
!= SPRT_YIELD_AARCH64
) {
262 ERROR("Unexpected return value 0x%llx\n", rc
);
266 ctx
->state
= SP_STATE_IDLE
;
268 INFO("Secure Partition %u initialized.\n", i
);
274 /*******************************************************************************
275 * Initialize contexts of all Secure Partitions.
276 ******************************************************************************/
277 int32_t spm_setup(void)
281 void *sp_base
, *rd_base
;
282 size_t sp_size
, rd_size
;
285 /* Disable MMU at EL1 (initialized by BL2) */
286 disable_mmu_icache_el1();
289 * Non-blocking services can be interrupted by Non-secure interrupts.
290 * Register an interrupt handler for NS interrupts when generated while
291 * the CPU is in secure state. They are routed to EL3.
293 set_interrupt_rm_flag(flags
, SECURE
);
295 uint64_t rc_int
= register_interrupt_type_handler(INTR_TYPE_NS
,
296 spm_ns_interrupt_handler
, flags
);
298 ERROR("SPM: Failed to register NS interrupt handler with rc = %llx\n",
304 * Setup all Secure Partitions.
309 rc
= plat_spm_sp_get_next_address(&sp_base
, &sp_size
,
312 /* Reached the end of the package. */
316 if (i
>= PLAT_SPM_MAX_PARTITIONS
) {
317 ERROR("Too many partitions in the package.\n");
321 ctx
= &sp_ctx_array
[i
];
323 assert(ctx
->is_present
== 0);
325 /* Initialize context of the SP */
326 INFO("Secure Partition %u context setup start...\n", i
);
328 /* Assign translation tables context. */
329 ctx
->xlat_ctx_handle
= spm_sp_xlat_context_alloc();
331 /* Save location of the image in physical memory */
332 ctx
->image_base
= (uintptr_t)sp_base
;
333 ctx
->image_size
= sp_size
;
335 rc
= plat_spm_sp_rd_load(&ctx
->rd
, rd_base
, rd_size
);
337 ERROR("Error while loading RD blob.\n");
345 INFO("Secure Partition %u setup done.\n", i
);
351 ERROR("No present partitions in the package.\n");
355 /* Register init function for deferred init. */
356 bl31_register_bl32_init(&spm_init
);