xref: /rk3399_ARM-atf/services/std_svc/spm/spm_mm/spm_mm_main.c (revision d57362bd92c2e5c8a1222fd763e24163c1234938)
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  ******************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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  ******************************************************************************/
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