xref: /rk3399_ARM-atf/services/std_svc/drtm/drtm_main.c (revision 2090e55283c4bf85c7a61735ca0e872745c55896)
1 /*
2  * Copyright (c) 2022 Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier:    BSD-3-Clause
5  *
6  * DRTM service
7  *
8  * Authors:
9  *	Lucian Paul-Trifu <lucian.paultrifu@gmail.com>
10  *	Brian Nezvadovitz <brinez@microsoft.com> 2021-02-01
11  */
12 
13 #include <stdint.h>
14 
15 #include <arch.h>
16 #include <arch_helpers.h>
17 #include <common/bl_common.h>
18 #include <common/debug.h>
19 #include <common/runtime_svc.h>
20 #include <drivers/auth/crypto_mod.h>
21 #include "drtm_main.h"
22 #include "drtm_measurements.h"
23 #include "drtm_remediation.h"
24 #include <lib/psci/psci_lib.h>
25 #include <lib/xlat_tables/xlat_tables_v2.h>
26 #include <plat/common/platform.h>
27 #include <services/drtm_svc.h>
28 #include <platform_def.h>
29 
30 /* Structure to store DRTM features specific to the platform. */
31 static drtm_features_t plat_drtm_features;
32 
33 /* DRTM-formatted memory map. */
34 static drtm_memory_region_descriptor_table_t *plat_drtm_mem_map;
35 
36 int drtm_setup(void)
37 {
38 	bool rc;
39 	const plat_drtm_tpm_features_t *plat_tpm_feat;
40 	const plat_drtm_dma_prot_features_t *plat_dma_prot_feat;
41 	uint64_t dlme_data_min_size;
42 
43 	INFO("DRTM service setup\n");
44 
45 	/* Read boot PE ID from MPIDR */
46 	plat_drtm_features.boot_pe_id = read_mpidr_el1() & MPIDR_AFFINITY_MASK;
47 
48 	rc = drtm_dma_prot_init();
49 	if (rc) {
50 		return INTERNAL_ERROR;
51 	}
52 
53 	/*
54 	 * initialise the platform supported crypto module that will
55 	 * be used by the DRTM-service to calculate hash of DRTM-
56 	 * implementation specific components
57 	 */
58 	crypto_mod_init();
59 
60 	/* Build DRTM-compatible address map. */
61 	plat_drtm_mem_map = drtm_build_address_map();
62 	if (plat_drtm_mem_map == NULL) {
63 		return INTERNAL_ERROR;
64 	}
65 
66 	/* Get DRTM features from platform hooks. */
67 	plat_tpm_feat = plat_drtm_get_tpm_features();
68 	if (plat_tpm_feat == NULL) {
69 		return INTERNAL_ERROR;
70 	}
71 
72 	plat_dma_prot_feat = plat_drtm_get_dma_prot_features();
73 	if (plat_dma_prot_feat == NULL) {
74 		return INTERNAL_ERROR;
75 	}
76 
77 	/*
78 	 * Add up minimum DLME data memory.
79 	 *
80 	 * For systems with complete DMA protection there is only one entry in
81 	 * the protected regions table.
82 	 */
83 	if (plat_dma_prot_feat->dma_protection_support ==
84 			ARM_DRTM_DMA_PROT_FEATURES_DMA_SUPPORT_COMPLETE) {
85 		dlme_data_min_size =
86 			sizeof(drtm_memory_region_descriptor_table_t) +
87 			sizeof(drtm_mem_region_t);
88 	} else {
89 		/*
90 		 * TODO set protected regions table size based on platform DMA
91 		 * protection configuration
92 		 */
93 		panic();
94 	}
95 
96 	dlme_data_min_size += (drtm_get_address_map_size() +
97 			       PLAT_DRTM_EVENT_LOG_MAX_SIZE +
98 			       plat_drtm_get_tcb_hash_table_size() +
99 			       plat_drtm_get_imp_def_dlme_region_size());
100 
101 	dlme_data_min_size = page_align(dlme_data_min_size, UP)/PAGE_SIZE;
102 
103 	/* Fill out platform DRTM features structure */
104 	/* Only support default PCR schema (0x1) in this implementation. */
105 	ARM_DRTM_TPM_FEATURES_SET_PCR_SCHEMA(plat_drtm_features.tpm_features,
106 		ARM_DRTM_TPM_FEATURES_PCR_SCHEMA_DEFAULT);
107 	ARM_DRTM_TPM_FEATURES_SET_TPM_HASH(plat_drtm_features.tpm_features,
108 		plat_tpm_feat->tpm_based_hash_support);
109 	ARM_DRTM_TPM_FEATURES_SET_FW_HASH(plat_drtm_features.tpm_features,
110 		plat_tpm_feat->firmware_hash_algorithm);
111 	ARM_DRTM_MIN_MEM_REQ_SET_MIN_DLME_DATA_SIZE(plat_drtm_features.minimum_memory_requirement,
112 		dlme_data_min_size);
113 	ARM_DRTM_MIN_MEM_REQ_SET_DCE_SIZE(plat_drtm_features.minimum_memory_requirement,
114 		plat_drtm_get_min_size_normal_world_dce());
115 	ARM_DRTM_DMA_PROT_FEATURES_SET_MAX_REGIONS(plat_drtm_features.dma_prot_features,
116 		plat_dma_prot_feat->max_num_mem_prot_regions);
117 	ARM_DRTM_DMA_PROT_FEATURES_SET_DMA_SUPPORT(plat_drtm_features.dma_prot_features,
118 		plat_dma_prot_feat->dma_protection_support);
119 	ARM_DRTM_TCB_HASH_FEATURES_SET_MAX_NUM_HASHES(plat_drtm_features.tcb_hash_features,
120 		plat_drtm_get_tcb_hash_features());
121 
122 	return 0;
123 }
124 
125 static inline uint64_t drtm_features_tpm(void *ctx)
126 {
127 	SMC_RET2(ctx, 1ULL, /* TPM feature is supported */
128 		 plat_drtm_features.tpm_features);
129 }
130 
131 static inline uint64_t drtm_features_mem_req(void *ctx)
132 {
133 	SMC_RET2(ctx, 1ULL, /* memory req Feature is supported */
134 		 plat_drtm_features.minimum_memory_requirement);
135 }
136 
137 static inline uint64_t drtm_features_boot_pe_id(void *ctx)
138 {
139 	SMC_RET2(ctx, 1ULL, /* Boot PE feature is supported */
140 		 plat_drtm_features.boot_pe_id);
141 }
142 
143 static inline uint64_t drtm_features_dma_prot(void *ctx)
144 {
145 	SMC_RET2(ctx, 1ULL, /* DMA protection feature is supported */
146 		 plat_drtm_features.dma_prot_features);
147 }
148 
149 static inline uint64_t drtm_features_tcb_hashes(void *ctx)
150 {
151 	SMC_RET2(ctx, 1ULL, /* TCB hash feature is supported */
152 		 plat_drtm_features.tcb_hash_features);
153 }
154 
155 static enum drtm_retc drtm_dl_check_caller_el(void *ctx)
156 {
157 	uint64_t spsr_el3 = read_ctx_reg(get_el3state_ctx(ctx), CTX_SPSR_EL3);
158 	uint64_t dl_caller_el;
159 	uint64_t dl_caller_aarch;
160 
161 	dl_caller_el = spsr_el3 >> MODE_EL_SHIFT & MODE_EL_MASK;
162 	dl_caller_aarch = spsr_el3 >> MODE_RW_SHIFT & MODE_RW_MASK;
163 
164 	/* Caller's security state is checked from drtm_smc_handle function */
165 
166 	/* Caller can be NS-EL2/EL1 */
167 	if (dl_caller_el == MODE_EL3) {
168 		ERROR("DRTM: invalid launch from EL3\n");
169 		return DENIED;
170 	}
171 
172 	if (dl_caller_aarch != MODE_RW_64) {
173 		ERROR("DRTM: invalid launch from non-AArch64 execution state\n");
174 		return DENIED;
175 	}
176 
177 	return SUCCESS;
178 }
179 
180 static enum drtm_retc drtm_dl_check_cores(void)
181 {
182 	bool running_on_single_core;
183 	uint64_t this_pe_aff_value = read_mpidr_el1() & MPIDR_AFFINITY_MASK;
184 
185 	if (this_pe_aff_value != plat_drtm_features.boot_pe_id) {
186 		ERROR("DRTM: invalid launch on a non-boot PE\n");
187 		return DENIED;
188 	}
189 
190 	running_on_single_core = psci_is_last_on_cpu_safe();
191 	if (!running_on_single_core) {
192 		ERROR("DRTM: invalid launch due to non-boot PE not being turned off\n");
193 		return DENIED;
194 	}
195 
196 	return SUCCESS;
197 }
198 
199 static enum drtm_retc drtm_dl_prepare_dlme_data(const struct_drtm_dl_args *args,
200 						size_t *dlme_data_size_out)
201 {
202 	size_t dlme_data_total_bytes_req = 0;
203 
204 	*dlme_data_size_out = dlme_data_total_bytes_req;
205 
206 	return SUCCESS;
207 }
208 
209 /*
210  * Note: accesses to the dynamic launch args, and to the DLME data are
211  * little-endian as required, thanks to TF-A BL31 init requirements.
212  */
213 static enum drtm_retc drtm_dl_check_args(uint64_t x1,
214 					 struct_drtm_dl_args *a_out)
215 {
216 	uint64_t dlme_start, dlme_end;
217 	uint64_t dlme_img_start, dlme_img_ep, dlme_img_end;
218 	uint64_t dlme_data_start, dlme_data_end;
219 	uintptr_t args_mapping;
220 	size_t args_mapping_size;
221 	struct_drtm_dl_args *a;
222 	struct_drtm_dl_args args_buf;
223 	size_t dlme_data_size_req;
224 	int rc;
225 
226 	if (x1 % DRTM_PAGE_SIZE != 0) {
227 		ERROR("DRTM: parameters structure is not "
228 		      DRTM_PAGE_SIZE_STR "-aligned\n");
229 		return INVALID_PARAMETERS;
230 	}
231 
232 	args_mapping_size = ALIGNED_UP(sizeof(struct_drtm_dl_args), DRTM_PAGE_SIZE);
233 	rc = mmap_add_dynamic_region_alloc_va(x1, &args_mapping, args_mapping_size,
234 					      MT_MEMORY | MT_NS | MT_RO |
235 					      MT_SHAREABILITY_ISH);
236 	if (rc != 0) {
237 		WARN("DRTM: %s: mmap_add_dynamic_region() failed rc=%d\n",
238 		      __func__, rc);
239 		return INTERNAL_ERROR;
240 	}
241 	a = (struct_drtm_dl_args *)args_mapping;
242 	/*
243 	 * TODO: invalidate all data cache before reading the data passed by the
244 	 * DCE Preamble.  This is required to avoid / defend against racing with
245 	 * cache evictions.
246 	 */
247 	args_buf = *a;
248 
249 	rc = mmap_remove_dynamic_region(args_mapping, args_mapping_size);
250 	if (rc) {
251 		ERROR("%s(): mmap_remove_dynamic_region() failed unexpectedly"
252 		      " rc=%d\n", __func__, rc);
253 		panic();
254 	}
255 	a = &args_buf;
256 
257 	if (a->version != 1) {
258 		ERROR("DRTM: parameters structure incompatible with major version %d\n",
259 		      ARM_DRTM_VERSION_MAJOR);
260 		return NOT_SUPPORTED;
261 	}
262 
263 	if (!(a->dlme_img_off < a->dlme_size &&
264 	      a->dlme_data_off < a->dlme_size)) {
265 		ERROR("DRTM: argument offset is outside of the DLME region\n");
266 		return INVALID_PARAMETERS;
267 	}
268 	dlme_start = a->dlme_paddr;
269 	dlme_end = a->dlme_paddr + a->dlme_size;
270 	dlme_img_start = a->dlme_paddr + a->dlme_img_off;
271 	dlme_img_ep = dlme_img_start + a->dlme_img_ep_off;
272 	dlme_img_end = dlme_img_start + a->dlme_img_size;
273 	dlme_data_start = a->dlme_paddr + a->dlme_data_off;
274 	dlme_data_end = dlme_end;
275 
276 	/*
277 	 * TODO: validate that the DLME physical address range is all NS memory,
278 	 * return INVALID_PARAMETERS if it is not.
279 	 * Note that this check relies on platform-specific information. For
280 	 * examples, see psci_plat_pm_ops->validate_ns_entrypoint() or
281 	 * arm_validate_ns_entrypoint().
282 	 */
283 
284 	/* Check the DLME regions arguments. */
285 	if ((dlme_start % DRTM_PAGE_SIZE) != 0) {
286 		ERROR("DRTM: argument DLME region is not "
287 		      DRTM_PAGE_SIZE_STR "-aligned\n");
288 		return INVALID_PARAMETERS;
289 	}
290 
291 	if (!(dlme_start < dlme_end &&
292 	      dlme_start <= dlme_img_start && dlme_img_start < dlme_img_end &&
293 	      dlme_start <= dlme_data_start && dlme_data_start < dlme_data_end)) {
294 		ERROR("DRTM: argument DLME region is discontiguous\n");
295 		return INVALID_PARAMETERS;
296 	}
297 
298 	if (dlme_img_start < dlme_data_end && dlme_data_start < dlme_img_end) {
299 		ERROR("DRTM: argument DLME regions overlap\n");
300 		return INVALID_PARAMETERS;
301 	}
302 
303 	/* Check the DLME image region arguments. */
304 	if ((dlme_img_start % DRTM_PAGE_SIZE) != 0) {
305 		ERROR("DRTM: argument DLME image region is not "
306 		      DRTM_PAGE_SIZE_STR "-aligned\n");
307 		return INVALID_PARAMETERS;
308 	}
309 
310 	if (!(dlme_img_start <= dlme_img_ep && dlme_img_ep < dlme_img_end)) {
311 		ERROR("DRTM: DLME entry point is outside of the DLME image region\n");
312 		return INVALID_PARAMETERS;
313 	}
314 
315 	if ((dlme_img_ep % 4) != 0) {
316 		ERROR("DRTM: DLME image entry point is not 4-byte-aligned\n");
317 		return INVALID_PARAMETERS;
318 	}
319 
320 	/* Check the DLME data region arguments. */
321 	if ((dlme_data_start % DRTM_PAGE_SIZE) != 0) {
322 		ERROR("DRTM: argument DLME data region is not "
323 		      DRTM_PAGE_SIZE_STR "-aligned\n");
324 		return INVALID_PARAMETERS;
325 	}
326 
327 	rc = drtm_dl_prepare_dlme_data(NULL, &dlme_data_size_req);
328 	if (rc) {
329 		ERROR("%s: drtm_dl_prepare_dlme_data() failed unexpectedly rc=%d\n",
330 		      __func__, rc);
331 		panic();
332 	}
333 	if (dlme_data_end - dlme_data_start < dlme_data_size_req) {
334 		ERROR("DRTM: argument DLME data region is short of %lu bytes\n",
335 		      dlme_data_size_req - (size_t)(dlme_data_end - dlme_data_start));
336 		return INVALID_PARAMETERS;
337 	}
338 
339 	/* Check the Normal World DCE region arguments. */
340 	if (a->dce_nwd_paddr != 0) {
341 		uint32_t dce_nwd_start = a->dce_nwd_paddr;
342 		uint32_t dce_nwd_end = dce_nwd_start + a->dce_nwd_size;
343 
344 		if (!(dce_nwd_start < dce_nwd_end)) {
345 			ERROR("DRTM: argument Normal World DCE region is dicontiguous\n");
346 			return INVALID_PARAMETERS;
347 		}
348 
349 		if (dce_nwd_start < dlme_end && dlme_start < dce_nwd_end) {
350 			ERROR("DRTM: argument Normal World DCE regions overlap\n");
351 			return INVALID_PARAMETERS;
352 		}
353 	}
354 
355 	*a_out = *a;
356 	return SUCCESS;
357 }
358 
359 static uint64_t drtm_dynamic_launch(uint64_t x1, void *handle)
360 {
361 	enum drtm_retc ret = SUCCESS;
362 	enum drtm_retc dma_prot_ret;
363 	struct_drtm_dl_args args;
364 
365 	/* Ensure that only boot PE is powered on */
366 	ret = drtm_dl_check_cores();
367 	if (ret != SUCCESS) {
368 		SMC_RET1(handle, ret);
369 	}
370 
371 	/*
372 	 * Ensure that execution state is AArch64 and the caller
373 	 * is highest non-secure exception level
374 	 */
375 	ret = drtm_dl_check_caller_el(handle);
376 	if (ret != SUCCESS) {
377 		SMC_RET1(handle, ret);
378 	}
379 
380 	ret = drtm_dl_check_args(x1, &args);
381 	if (ret != SUCCESS) {
382 		SMC_RET1(handle, ret);
383 	}
384 
385 	/*
386 	 * Engage the DMA protections.  The launch cannot proceed without the DMA
387 	 * protections due to potential TOC/TOU vulnerabilities w.r.t. the DLME
388 	 * region (and to the NWd DCE region).
389 	 */
390 	ret = drtm_dma_prot_engage(&args.dma_prot_args,
391 				   DL_ARGS_GET_DMA_PROT_TYPE(&args));
392 	if (ret != SUCCESS) {
393 		SMC_RET1(handle, ret);
394 	}
395 
396 	/*
397 	 * The DMA protection is now engaged.  Note that any failure mode that
398 	 * returns an error to the DRTM-launch caller must now disengage DMA
399 	 * protections before returning to the caller.
400 	 */
401 
402 	ret = drtm_take_measurements(&args);
403 	if (ret != SUCCESS) {
404 		goto err_undo_dma_prot;
405 	}
406 
407 	SMC_RET1(handle, ret);
408 
409 err_undo_dma_prot:
410 	dma_prot_ret = drtm_dma_prot_disengage();
411 	if (dma_prot_ret != SUCCESS) {
412 		ERROR("%s(): drtm_dma_prot_disengage() failed unexpectedly"
413 		      " rc=%d\n", __func__, ret);
414 		panic();
415 	}
416 
417 	SMC_RET1(handle, ret);
418 }
419 
420 uint64_t drtm_smc_handler(uint32_t smc_fid,
421 			  uint64_t x1,
422 			  uint64_t x2,
423 			  uint64_t x3,
424 			  uint64_t x4,
425 			  void *cookie,
426 			  void *handle,
427 			  uint64_t flags)
428 {
429 	/* Check that the SMC call is from the Normal World. */
430 	if (!is_caller_non_secure(flags)) {
431 		SMC_RET1(handle, NOT_SUPPORTED);
432 	}
433 
434 	switch (smc_fid) {
435 	case ARM_DRTM_SVC_VERSION:
436 		INFO("DRTM service handler: version\n");
437 		/* Return the version of current implementation */
438 		SMC_RET1(handle, ARM_DRTM_VERSION);
439 		break;	/* not reached */
440 
441 	case ARM_DRTM_SVC_FEATURES:
442 		if (((x1 >> ARM_DRTM_FUNC_SHIFT) & ARM_DRTM_FUNC_MASK) ==
443 		    ARM_DRTM_FUNC_ID) {
444 			/* Dispatch function-based queries. */
445 			switch (x1 & FUNCID_MASK) {
446 			case ARM_DRTM_SVC_VERSION:
447 				SMC_RET1(handle, SUCCESS);
448 				break;	/* not reached */
449 
450 			case ARM_DRTM_SVC_FEATURES:
451 				SMC_RET1(handle, SUCCESS);
452 				break;	/* not reached */
453 
454 			case ARM_DRTM_SVC_UNPROTECT_MEM:
455 				SMC_RET1(handle, SUCCESS);
456 				break;	/* not reached */
457 
458 			case ARM_DRTM_SVC_DYNAMIC_LAUNCH:
459 				SMC_RET1(handle, SUCCESS);
460 				break;	/* not reached */
461 
462 			case ARM_DRTM_SVC_CLOSE_LOCALITY:
463 				WARN("ARM_DRTM_SVC_CLOSE_LOCALITY feature %s",
464 				     "is not supported\n");
465 				SMC_RET1(handle, NOT_SUPPORTED);
466 				break;	/* not reached */
467 
468 			case ARM_DRTM_SVC_GET_ERROR:
469 				SMC_RET1(handle, SUCCESS);
470 				break;	/* not reached */
471 
472 			case ARM_DRTM_SVC_SET_ERROR:
473 				SMC_RET1(handle, SUCCESS);
474 				break;	/* not reached */
475 
476 			case ARM_DRTM_SVC_SET_TCB_HASH:
477 				WARN("ARM_DRTM_SVC_TCB_HASH feature %s",
478 				     "is not supported\n");
479 				SMC_RET1(handle, NOT_SUPPORTED);
480 				break;	/* not reached */
481 
482 			case ARM_DRTM_SVC_LOCK_TCB_HASH:
483 				WARN("ARM_DRTM_SVC_LOCK_TCB_HASH feature %s",
484 				     "is not supported\n");
485 				SMC_RET1(handle, NOT_SUPPORTED);
486 				break;	/* not reached */
487 
488 			default:
489 				ERROR("Unknown DRTM service function\n");
490 				SMC_RET1(handle, NOT_SUPPORTED);
491 				break;	/* not reached */
492 			}
493 		} else {
494 			/* Dispatch feature-based queries. */
495 			switch (x1 & ARM_DRTM_FEAT_ID_MASK) {
496 			case ARM_DRTM_FEATURES_TPM:
497 				INFO("++ DRTM service handler: TPM features\n");
498 				return drtm_features_tpm(handle);
499 				break;	/* not reached */
500 
501 			case ARM_DRTM_FEATURES_MEM_REQ:
502 				INFO("++ DRTM service handler: Min. mem."
503 				     " requirement features\n");
504 				return drtm_features_mem_req(handle);
505 				break;	/* not reached */
506 
507 			case ARM_DRTM_FEATURES_DMA_PROT:
508 				INFO("++ DRTM service handler: "
509 				     "DMA protection features\n");
510 				return drtm_features_dma_prot(handle);
511 				break;	/* not reached */
512 
513 			case ARM_DRTM_FEATURES_BOOT_PE_ID:
514 				INFO("++ DRTM service handler: "
515 				     "Boot PE ID features\n");
516 				return drtm_features_boot_pe_id(handle);
517 				break;	/* not reached */
518 
519 			case ARM_DRTM_FEATURES_TCB_HASHES:
520 				INFO("++ DRTM service handler: "
521 				     "TCB-hashes features\n");
522 				return drtm_features_tcb_hashes(handle);
523 				break;	/* not reached */
524 
525 			default:
526 				ERROR("Unknown ARM DRTM service feature\n");
527 				SMC_RET1(handle, NOT_SUPPORTED);
528 				break;	/* not reached */
529 			}
530 		}
531 
532 	case ARM_DRTM_SVC_UNPROTECT_MEM:
533 		INFO("DRTM service handler: unprotect mem\n");
534 		return drtm_unprotect_mem(handle);
535 		break;	/* not reached */
536 
537 	case ARM_DRTM_SVC_DYNAMIC_LAUNCH:
538 		INFO("DRTM service handler: dynamic launch\n");
539 		return drtm_dynamic_launch(x1, handle);
540 		break;	/* not reached */
541 
542 	case ARM_DRTM_SVC_CLOSE_LOCALITY:
543 		WARN("DRTM service handler: close locality %s\n",
544 		     "is not supported");
545 		SMC_RET1(handle, NOT_SUPPORTED);
546 		break;	/* not reached */
547 
548 	case ARM_DRTM_SVC_GET_ERROR:
549 		INFO("DRTM service handler: get error\n");
550 		drtm_get_error(handle);
551 		break;	/* not reached */
552 
553 	case ARM_DRTM_SVC_SET_ERROR:
554 		INFO("DRTM service handler: set error\n");
555 		drtm_set_error(x1, handle);
556 		break;	/* not reached */
557 
558 	case ARM_DRTM_SVC_SET_TCB_HASH:
559 		WARN("DRTM service handler: set TCB hash %s\n",
560 		     "is not supported");
561 		SMC_RET1(handle, NOT_SUPPORTED);
562 		break;  /* not reached */
563 
564 	case ARM_DRTM_SVC_LOCK_TCB_HASH:
565 		WARN("DRTM service handler: lock TCB hash %s\n",
566 		     "is not supported");
567 		SMC_RET1(handle, NOT_SUPPORTED);
568 		break;  /* not reached */
569 
570 	default:
571 		ERROR("Unknown DRTM service function: 0x%x\n", smc_fid);
572 		SMC_RET1(handle, SMC_UNK);
573 		break;	/* not reached */
574 	}
575 
576 	/* not reached */
577 	SMC_RET1(handle, SMC_UNK);
578 }
579