1 /*
2 * Copyright (c) 2017-2025, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <arch_helpers.h>
8 #include <assert.h>
9 #include <errno.h>
10
11 #include <bl31/bl31.h>
12 #include <bl31/ehf.h>
13 #include <common/debug.h>
14 #include <common/runtime_svc.h>
15 #include <lib/el3_runtime/context_mgmt.h>
16 #include <lib/el3_runtime/simd_ctx.h>
17 #include <lib/smccc.h>
18 #include <lib/spinlock.h>
19 #include <lib/utils.h>
20 #include <lib/xlat_tables/xlat_tables_v2.h>
21 #include <plat/common/platform.h>
22 #include <services/spm_mm_partition.h>
23 #include <services/spm_mm_svc.h>
24 #include <services/ven_el3_svc.h>
25 #include <smccc_helpers.h>
26
27 #include "spm_common.h"
28 #include "spm_mm_private.h"
29
30 /*******************************************************************************
31 * Secure Partition context information.
32 ******************************************************************************/
33 static sp_context_t sp_ctx;
34
35 /********************************************************************************
36 * TPM service UUID: 17b862a4-1806-4faf-86b3-089a58353861 as mentioned in
37 * https://developer.arm.com/documentation/den0138/latest/
38 *******************************************************************************/
39 DEFINE_SVC_UUID2(tpm_service_uuid,
40 0x17b862a4, 0x1806, 0x4faf, 0x86, 0xb3,
41 0x08, 0x9a, 0x58, 0x35, 0x38, 0x61);
42
43 /*******************************************************************************
44 * Set state of a Secure Partition context.
45 ******************************************************************************/
sp_state_set(sp_context_t * sp_ptr,sp_state_t state)46 static void sp_state_set(sp_context_t *sp_ptr, sp_state_t state)
47 {
48 sp_ptr->state = state;
49 spin_unlock(&(sp_ptr->state_lock));
50 }
51
52 /*******************************************************************************
53 * Change the state of a Secure Partition to the one specified.
54 ******************************************************************************/
sp_state_wait_switch(sp_context_t * sp_ptr,sp_state_t from,sp_state_t to)55 static void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to)
56 {
57 spin_lock(&(sp_ptr->state_lock));
58 sp_ptr->state = to;
59 }
60
61 /*******************************************************************************
62 * This function takes an SP context pointer and performs a synchronous entry
63 * into it.
64 ******************************************************************************/
spm_sp_synchronous_entry(sp_context_t * ctx)65 static uint64_t spm_sp_synchronous_entry(sp_context_t *ctx)
66 {
67 uint64_t rc;
68
69 assert(ctx != NULL);
70
71 /* Assign the context of the SP to this CPU */
72 cm_set_context(&(ctx->cpu_ctx), SECURE);
73
74 /* Restore the context assigned above */
75 cm_el1_sysregs_context_restore(SECURE);
76 cm_set_next_eret_context(SECURE);
77
78 /* Invalidate TLBs at EL1. */
79 tlbivmalle1();
80 dsbish();
81
82 /* Enter Secure Partition */
83 rc = spm_secure_partition_enter(&ctx->c_rt_ctx);
84
85 /* Save secure state */
86 cm_el1_sysregs_context_save(SECURE);
87
88 return rc;
89 }
90
91 /*******************************************************************************
92 * This function returns to the place where spm_sp_synchronous_entry() was
93 * called originally.
94 ******************************************************************************/
spm_sp_synchronous_exit(uint64_t rc)95 __dead2 static void spm_sp_synchronous_exit(uint64_t rc)
96 {
97 sp_context_t *ctx = &sp_ctx;
98
99 /*
100 * The SPM must have initiated the original request through a
101 * synchronous entry into the secure partition. Jump back to the
102 * original C runtime context with the value of rc in x0;
103 */
104 spm_secure_partition_exit(ctx->c_rt_ctx, rc);
105
106 panic();
107 }
108
109 /*******************************************************************************
110 * Jump to each Secure Partition for the first time.
111 ******************************************************************************/
spm_init(void)112 static int32_t spm_init(void)
113 {
114 uint64_t rc;
115 sp_context_t *ctx;
116
117 INFO("Secure Partition init...\n");
118
119 ctx = &sp_ctx;
120
121 ctx->state = SP_STATE_RESET;
122
123 rc = spm_sp_synchronous_entry(ctx);
124 assert(rc == 0);
125
126 ctx->state = SP_STATE_IDLE;
127
128 INFO("Secure Partition initialized.\n");
129
130 return !rc;
131 }
132
133 /*******************************************************************************
134 * Initialize contexts of all Secure Partitions.
135 ******************************************************************************/
spm_mm_setup(void)136 int32_t spm_mm_setup(void)
137 {
138 sp_context_t *ctx;
139
140 /* Disable MMU at EL1 (initialized by BL2) */
141 disable_mmu_icache_el1();
142
143 /* Initialize context of the SP */
144 INFO("Secure Partition context setup start...\n");
145
146 ctx = &sp_ctx;
147
148 /* Assign translation tables context. */
149 ctx->xlat_ctx_handle = spm_get_sp_xlat_context();
150
151 spm_sp_setup(ctx);
152
153 /* Register init function for deferred init. */
154 bl31_register_bl32_init(&spm_init);
155
156 INFO("Secure Partition setup done.\n");
157
158 return 0;
159 }
160
161 /*******************************************************************************
162 * Function to perform a call to a Secure Partition.
163 ******************************************************************************/
spm_mm_sp_call(uint32_t smc_fid,uint64_t x1,uint64_t x2,uint64_t x3)164 uint64_t spm_mm_sp_call(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3)
165 {
166 uint64_t rc;
167 sp_context_t *sp_ptr = &sp_ctx;
168
169 #if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
170 /*
171 * SP runs to completion, no need to restore FP/SVE registers of secure context.
172 * Save FP/SVE registers only for non secure context.
173 */
174 simd_ctx_save(NON_SECURE, false);
175 #endif /* CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS */
176
177 /* Wait until the Secure Partition is idle and set it to busy. */
178 sp_state_wait_switch(sp_ptr, SP_STATE_IDLE, SP_STATE_BUSY);
179
180 /* Set values for registers on SP entry */
181 cpu_context_t *cpu_ctx = &(sp_ptr->cpu_ctx);
182
183 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X0, smc_fid);
184 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1, x1);
185 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X2, x2);
186 write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3, x3);
187
188 /* Jump to the Secure Partition. */
189 rc = spm_sp_synchronous_entry(sp_ptr);
190
191 /* Flag Secure Partition as idle. */
192 assert(sp_ptr->state == SP_STATE_BUSY);
193 sp_state_set(sp_ptr, SP_STATE_IDLE);
194
195 #if CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS
196 /*
197 * SP runs to completion, no need to save FP/SVE registers of secure context.
198 * Restore only non secure world FP/SVE registers.
199 */
200 simd_ctx_restore(NON_SECURE);
201 #endif /* CTX_INCLUDE_FPREGS || CTX_INCLUDE_SVE_REGS */
202
203 return rc;
204 }
205
206 /*******************************************************************************
207 * MM_COMMUNICATE handler
208 ******************************************************************************/
mm_communicate(uint32_t smc_fid,uint64_t mm_cookie,uint64_t comm_buffer_address,uint64_t comm_size_address,void * handle)209 static uint64_t mm_communicate(uint32_t smc_fid, uint64_t mm_cookie,
210 uint64_t comm_buffer_address,
211 uint64_t comm_size_address, void *handle)
212 {
213 uint64_t rc;
214
215 /* Cookie. Reserved for future use. It must be zero. */
216 if (mm_cookie != 0U) {
217 ERROR("MM_COMMUNICATE: cookie is not zero\n");
218 SMC_RET1(handle, SPM_MM_INVALID_PARAMETER);
219 }
220
221 if (comm_buffer_address == 0U) {
222 ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n");
223 SMC_RET1(handle, SPM_MM_INVALID_PARAMETER);
224 }
225
226 if (comm_size_address != 0U) {
227 VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n");
228 }
229
230 /*
231 * The current secure partition design mandates
232 * - at any point, only a single core can be
233 * executing in the secure partition.
234 * - a core cannot be preempted by an interrupt
235 * while executing in secure partition.
236 * Raise the running priority of the core to the
237 * interrupt level configured for secure partition
238 * so as to block any interrupt from preempting this
239 * core.
240 */
241 ehf_activate_priority(PLAT_SP_PRI);
242
243 /* Save the Normal world context */
244 cm_el1_sysregs_context_save(NON_SECURE);
245
246 rc = spm_mm_sp_call(smc_fid, comm_buffer_address, comm_size_address,
247 plat_my_core_pos());
248
249 /* Restore non-secure state */
250 cm_el1_sysregs_context_restore(NON_SECURE);
251 cm_set_next_eret_context(NON_SECURE);
252
253 /*
254 * Exited from secure partition. This core can take
255 * interrupts now.
256 */
257 ehf_deactivate_priority(PLAT_SP_PRI);
258
259 SMC_RET1(handle, rc);
260 }
261
262 /*******************************************************************************
263 * SPM_MM TPM start handler as mentioned in section 3.3.1 of TCG ACPI
264 * specification version 1.4
265 ******************************************************************************/
spm_mm_tpm_start_handler(uint32_t smc_fid,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)266 uint64_t spm_mm_tpm_start_handler(uint32_t smc_fid,
267 uint64_t x1,
268 uint64_t x2,
269 uint64_t x3,
270 uint64_t x4,
271 void *cookie,
272 void *handle,
273 uint64_t flags)
274 {
275 mm_communicate_header_t *mm_comm_header = (void *)PLAT_SPM_BUF_BASE;
276 uint32_t spm_mm_smc_fid;
277
278 if (!is_caller_non_secure(flags)) {
279 ERROR("spm_mm TPM START must be requested from normal world only.\n");
280 SMC_RET1(handle, SMC_UNK);
281 }
282
283 switch (smc_fid) {
284 case TPM_START_SMC_32:
285 spm_mm_smc_fid = MM_COMMUNICATE_AARCH32;
286 break;
287 case TPM_START_SMC_64:
288 spm_mm_smc_fid = MM_COMMUNICATE_AARCH64;
289 break;
290 default:
291 ERROR("Unexpected SMC FID\n");
292 SMC_RET1(handle, SMC_UNK);
293 break;
294 }
295
296 memset(mm_comm_header, 0U, sizeof(mm_communicate_header_t));
297 memcpy(&mm_comm_header->header_guid, &tpm_service_uuid, sizeof(struct efi_guid));
298
299 return mm_communicate(spm_mm_smc_fid, x1, (uint64_t)mm_comm_header, x3, handle);
300 }
301
302 /*******************************************************************************
303 * Secure Partition Manager SMC handler.
304 ******************************************************************************/
spm_mm_smc_handler(uint32_t smc_fid,uint64_t x1,uint64_t x2,uint64_t x3,uint64_t x4,void * cookie,void * handle,uint64_t flags)305 uint64_t spm_mm_smc_handler(uint32_t smc_fid,
306 uint64_t x1,
307 uint64_t x2,
308 uint64_t x3,
309 uint64_t x4,
310 void *cookie,
311 void *handle,
312 uint64_t flags)
313 {
314 unsigned int ns;
315 int32_t ret;
316 uint32_t attr;
317 uint32_t page_count;
318
319 /* Determine which security state this SMC originated from */
320 ns = is_caller_non_secure(flags);
321
322 if (ns == SMC_FROM_SECURE) {
323
324 /* Handle SMCs from Secure world. */
325
326 assert(handle == cm_get_context(SECURE));
327
328 /* Make next ERET jump to S-EL0 instead of S-EL1. */
329 cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1());
330
331 switch (smc_fid) {
332
333 case SPM_MM_VERSION_AARCH32:
334 SMC_RET1(handle, SPM_MM_VERSION_COMPILED);
335
336 case MM_SP_EVENT_COMPLETE_AARCH64:
337 spm_sp_synchronous_exit(x1);
338
339 case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
340 INFO("Received MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n");
341
342 if (sp_ctx.state != SP_STATE_RESET) {
343 WARN("MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n");
344 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
345 }
346
347 /* x2 = page_count - 1 */
348 page_count = x2 + 1;
349
350 ret = spm_memory_attributes_get_smc_handler(
351 &sp_ctx, x1, &page_count, &attr);
352 if (ret != SPM_MM_SUCCESS) {
353 SMC_RET1(handle, ret);
354 } else {
355 SMC_RET2(handle, attr, --page_count);
356 }
357
358 case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
359 INFO("Received MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n");
360
361 if (sp_ctx.state != SP_STATE_RESET) {
362 WARN("MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n");
363 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
364 }
365 SMC_RET1(handle,
366 spm_memory_attributes_set_smc_handler(
367 &sp_ctx, x1, x2, x3));
368 default:
369 break;
370 }
371 } else {
372
373 /* Handle SMCs from Non-secure world. */
374
375 assert(handle == cm_get_context(NON_SECURE));
376
377 switch (smc_fid) {
378
379 case MM_VERSION_AARCH32:
380 SMC_RET1(handle, MM_VERSION_COMPILED);
381
382 case MM_COMMUNICATE_AARCH32:
383 case MM_COMMUNICATE_AARCH64:
384 return mm_communicate(smc_fid, x1, x2, x3, handle);
385
386 case MM_SP_MEMORY_ATTRIBUTES_GET_AARCH64:
387 case MM_SP_MEMORY_ATTRIBUTES_SET_AARCH64:
388 /* SMC interfaces reserved for secure callers. */
389 SMC_RET1(handle, SPM_MM_NOT_SUPPORTED);
390
391 default:
392 break;
393 }
394 }
395
396 SMC_RET1(handle, SMC_UNK);
397 }
398