xref: /arm-trusted-firmware/services/std_svc/drtm/drtm_main.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2022 Arm Limited. All rights reserved.
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier:    BSD-3-Clause
5*91f16700Schasinglulu  *
6*91f16700Schasinglulu  * DRTM service
7*91f16700Schasinglulu  *
8*91f16700Schasinglulu  * Authors:
9*91f16700Schasinglulu  *	Lucian Paul-Trifu <lucian.paultrifu@gmail.com>
10*91f16700Schasinglulu  *	Brian Nezvadovitz <brinez@microsoft.com> 2021-02-01
11*91f16700Schasinglulu  */
12*91f16700Schasinglulu 
13*91f16700Schasinglulu #include <stdint.h>
14*91f16700Schasinglulu 
15*91f16700Schasinglulu #include <arch.h>
16*91f16700Schasinglulu #include <arch_helpers.h>
17*91f16700Schasinglulu #include <common/bl_common.h>
18*91f16700Schasinglulu #include <common/debug.h>
19*91f16700Schasinglulu #include <common/runtime_svc.h>
20*91f16700Schasinglulu #include <drivers/auth/crypto_mod.h>
21*91f16700Schasinglulu #include "drtm_main.h"
22*91f16700Schasinglulu #include "drtm_measurements.h"
23*91f16700Schasinglulu #include "drtm_remediation.h"
24*91f16700Schasinglulu #include <lib/el3_runtime/context_mgmt.h>
25*91f16700Schasinglulu #include <lib/psci/psci_lib.h>
26*91f16700Schasinglulu #include <lib/xlat_tables/xlat_tables_v2.h>
27*91f16700Schasinglulu #include <plat/common/platform.h>
28*91f16700Schasinglulu #include <services/drtm_svc.h>
29*91f16700Schasinglulu #include <services/sdei.h>
30*91f16700Schasinglulu #include <platform_def.h>
31*91f16700Schasinglulu 
32*91f16700Schasinglulu /* Structure to store DRTM features specific to the platform. */
33*91f16700Schasinglulu static drtm_features_t plat_drtm_features;
34*91f16700Schasinglulu 
35*91f16700Schasinglulu /* DRTM-formatted memory map. */
36*91f16700Schasinglulu static drtm_memory_region_descriptor_table_t *plat_drtm_mem_map;
37*91f16700Schasinglulu 
38*91f16700Schasinglulu /* DLME header */
39*91f16700Schasinglulu struct_dlme_data_header dlme_data_hdr_init;
40*91f16700Schasinglulu 
41*91f16700Schasinglulu /* Minimum data memory requirement */
42*91f16700Schasinglulu uint64_t dlme_data_min_size;
43*91f16700Schasinglulu 
44*91f16700Schasinglulu int drtm_setup(void)
45*91f16700Schasinglulu {
46*91f16700Schasinglulu 	bool rc;
47*91f16700Schasinglulu 	const plat_drtm_tpm_features_t *plat_tpm_feat;
48*91f16700Schasinglulu 	const plat_drtm_dma_prot_features_t *plat_dma_prot_feat;
49*91f16700Schasinglulu 
50*91f16700Schasinglulu 	INFO("DRTM service setup\n");
51*91f16700Schasinglulu 
52*91f16700Schasinglulu 	/* Read boot PE ID from MPIDR */
53*91f16700Schasinglulu 	plat_drtm_features.boot_pe_id = read_mpidr_el1() & MPIDR_AFFINITY_MASK;
54*91f16700Schasinglulu 
55*91f16700Schasinglulu 	rc = drtm_dma_prot_init();
56*91f16700Schasinglulu 	if (rc) {
57*91f16700Schasinglulu 		return INTERNAL_ERROR;
58*91f16700Schasinglulu 	}
59*91f16700Schasinglulu 
60*91f16700Schasinglulu 	/*
61*91f16700Schasinglulu 	 * initialise the platform supported crypto module that will
62*91f16700Schasinglulu 	 * be used by the DRTM-service to calculate hash of DRTM-
63*91f16700Schasinglulu 	 * implementation specific components
64*91f16700Schasinglulu 	 */
65*91f16700Schasinglulu 	crypto_mod_init();
66*91f16700Schasinglulu 
67*91f16700Schasinglulu 	/* Build DRTM-compatible address map. */
68*91f16700Schasinglulu 	plat_drtm_mem_map = drtm_build_address_map();
69*91f16700Schasinglulu 	if (plat_drtm_mem_map == NULL) {
70*91f16700Schasinglulu 		return INTERNAL_ERROR;
71*91f16700Schasinglulu 	}
72*91f16700Schasinglulu 
73*91f16700Schasinglulu 	/* Get DRTM features from platform hooks. */
74*91f16700Schasinglulu 	plat_tpm_feat = plat_drtm_get_tpm_features();
75*91f16700Schasinglulu 	if (plat_tpm_feat == NULL) {
76*91f16700Schasinglulu 		return INTERNAL_ERROR;
77*91f16700Schasinglulu 	}
78*91f16700Schasinglulu 
79*91f16700Schasinglulu 	plat_dma_prot_feat = plat_drtm_get_dma_prot_features();
80*91f16700Schasinglulu 	if (plat_dma_prot_feat == NULL) {
81*91f16700Schasinglulu 		return INTERNAL_ERROR;
82*91f16700Schasinglulu 	}
83*91f16700Schasinglulu 
84*91f16700Schasinglulu 	/*
85*91f16700Schasinglulu 	 * Add up minimum DLME data memory.
86*91f16700Schasinglulu 	 *
87*91f16700Schasinglulu 	 * For systems with complete DMA protection there is only one entry in
88*91f16700Schasinglulu 	 * the protected regions table.
89*91f16700Schasinglulu 	 */
90*91f16700Schasinglulu 	if (plat_dma_prot_feat->dma_protection_support ==
91*91f16700Schasinglulu 			ARM_DRTM_DMA_PROT_FEATURES_DMA_SUPPORT_COMPLETE) {
92*91f16700Schasinglulu 		dlme_data_min_size =
93*91f16700Schasinglulu 			sizeof(drtm_memory_region_descriptor_table_t) +
94*91f16700Schasinglulu 			sizeof(drtm_mem_region_t);
95*91f16700Schasinglulu 		dlme_data_hdr_init.dlme_prot_regions_size = dlme_data_min_size;
96*91f16700Schasinglulu 	} else {
97*91f16700Schasinglulu 		/*
98*91f16700Schasinglulu 		 * TODO set protected regions table size based on platform DMA
99*91f16700Schasinglulu 		 * protection configuration
100*91f16700Schasinglulu 		 */
101*91f16700Schasinglulu 		panic();
102*91f16700Schasinglulu 	}
103*91f16700Schasinglulu 
104*91f16700Schasinglulu 	dlme_data_hdr_init.dlme_addr_map_size = drtm_get_address_map_size();
105*91f16700Schasinglulu 	dlme_data_hdr_init.dlme_tcb_hashes_table_size =
106*91f16700Schasinglulu 				plat_drtm_get_tcb_hash_table_size();
107*91f16700Schasinglulu 	dlme_data_hdr_init.dlme_impdef_region_size =
108*91f16700Schasinglulu 				plat_drtm_get_imp_def_dlme_region_size();
109*91f16700Schasinglulu 
110*91f16700Schasinglulu 	dlme_data_min_size += dlme_data_hdr_init.dlme_addr_map_size +
111*91f16700Schasinglulu 			      PLAT_DRTM_EVENT_LOG_MAX_SIZE +
112*91f16700Schasinglulu 			      dlme_data_hdr_init.dlme_tcb_hashes_table_size +
113*91f16700Schasinglulu 			      dlme_data_hdr_init.dlme_impdef_region_size;
114*91f16700Schasinglulu 
115*91f16700Schasinglulu 	dlme_data_min_size = page_align(dlme_data_min_size, UP)/PAGE_SIZE;
116*91f16700Schasinglulu 
117*91f16700Schasinglulu 	/* Fill out platform DRTM features structure */
118*91f16700Schasinglulu 	/* Only support default PCR schema (0x1) in this implementation. */
119*91f16700Schasinglulu 	ARM_DRTM_TPM_FEATURES_SET_PCR_SCHEMA(plat_drtm_features.tpm_features,
120*91f16700Schasinglulu 		ARM_DRTM_TPM_FEATURES_PCR_SCHEMA_DEFAULT);
121*91f16700Schasinglulu 	ARM_DRTM_TPM_FEATURES_SET_TPM_HASH(plat_drtm_features.tpm_features,
122*91f16700Schasinglulu 		plat_tpm_feat->tpm_based_hash_support);
123*91f16700Schasinglulu 	ARM_DRTM_TPM_FEATURES_SET_FW_HASH(plat_drtm_features.tpm_features,
124*91f16700Schasinglulu 		plat_tpm_feat->firmware_hash_algorithm);
125*91f16700Schasinglulu 	ARM_DRTM_MIN_MEM_REQ_SET_MIN_DLME_DATA_SIZE(plat_drtm_features.minimum_memory_requirement,
126*91f16700Schasinglulu 		dlme_data_min_size);
127*91f16700Schasinglulu 	ARM_DRTM_MIN_MEM_REQ_SET_DCE_SIZE(plat_drtm_features.minimum_memory_requirement,
128*91f16700Schasinglulu 		plat_drtm_get_min_size_normal_world_dce());
129*91f16700Schasinglulu 	ARM_DRTM_DMA_PROT_FEATURES_SET_MAX_REGIONS(plat_drtm_features.dma_prot_features,
130*91f16700Schasinglulu 		plat_dma_prot_feat->max_num_mem_prot_regions);
131*91f16700Schasinglulu 	ARM_DRTM_DMA_PROT_FEATURES_SET_DMA_SUPPORT(plat_drtm_features.dma_prot_features,
132*91f16700Schasinglulu 		plat_dma_prot_feat->dma_protection_support);
133*91f16700Schasinglulu 	ARM_DRTM_TCB_HASH_FEATURES_SET_MAX_NUM_HASHES(plat_drtm_features.tcb_hash_features,
134*91f16700Schasinglulu 		plat_drtm_get_tcb_hash_features());
135*91f16700Schasinglulu 
136*91f16700Schasinglulu 	return 0;
137*91f16700Schasinglulu }
138*91f16700Schasinglulu 
139*91f16700Schasinglulu static inline void invalidate_icache_all(void)
140*91f16700Schasinglulu {
141*91f16700Schasinglulu 	__asm__ volatile("ic      ialluis");
142*91f16700Schasinglulu 	dsb();
143*91f16700Schasinglulu 	isb();
144*91f16700Schasinglulu }
145*91f16700Schasinglulu 
146*91f16700Schasinglulu static inline uint64_t drtm_features_tpm(void *ctx)
147*91f16700Schasinglulu {
148*91f16700Schasinglulu 	SMC_RET2(ctx, 1ULL, /* TPM feature is supported */
149*91f16700Schasinglulu 		 plat_drtm_features.tpm_features);
150*91f16700Schasinglulu }
151*91f16700Schasinglulu 
152*91f16700Schasinglulu static inline uint64_t drtm_features_mem_req(void *ctx)
153*91f16700Schasinglulu {
154*91f16700Schasinglulu 	SMC_RET2(ctx, 1ULL, /* memory req Feature is supported */
155*91f16700Schasinglulu 		 plat_drtm_features.minimum_memory_requirement);
156*91f16700Schasinglulu }
157*91f16700Schasinglulu 
158*91f16700Schasinglulu static inline uint64_t drtm_features_boot_pe_id(void *ctx)
159*91f16700Schasinglulu {
160*91f16700Schasinglulu 	SMC_RET2(ctx, 1ULL, /* Boot PE feature is supported */
161*91f16700Schasinglulu 		 plat_drtm_features.boot_pe_id);
162*91f16700Schasinglulu }
163*91f16700Schasinglulu 
164*91f16700Schasinglulu static inline uint64_t drtm_features_dma_prot(void *ctx)
165*91f16700Schasinglulu {
166*91f16700Schasinglulu 	SMC_RET2(ctx, 1ULL, /* DMA protection feature is supported */
167*91f16700Schasinglulu 		 plat_drtm_features.dma_prot_features);
168*91f16700Schasinglulu }
169*91f16700Schasinglulu 
170*91f16700Schasinglulu static inline uint64_t drtm_features_tcb_hashes(void *ctx)
171*91f16700Schasinglulu {
172*91f16700Schasinglulu 	SMC_RET2(ctx, 1ULL, /* TCB hash feature is supported */
173*91f16700Schasinglulu 		 plat_drtm_features.tcb_hash_features);
174*91f16700Schasinglulu }
175*91f16700Schasinglulu 
176*91f16700Schasinglulu static enum drtm_retc drtm_dl_check_caller_el(void *ctx)
177*91f16700Schasinglulu {
178*91f16700Schasinglulu 	uint64_t spsr_el3 = read_ctx_reg(get_el3state_ctx(ctx), CTX_SPSR_EL3);
179*91f16700Schasinglulu 	uint64_t dl_caller_el;
180*91f16700Schasinglulu 	uint64_t dl_caller_aarch;
181*91f16700Schasinglulu 
182*91f16700Schasinglulu 	dl_caller_el = spsr_el3 >> MODE_EL_SHIFT & MODE_EL_MASK;
183*91f16700Schasinglulu 	dl_caller_aarch = spsr_el3 >> MODE_RW_SHIFT & MODE_RW_MASK;
184*91f16700Schasinglulu 
185*91f16700Schasinglulu 	/* Caller's security state is checked from drtm_smc_handle function */
186*91f16700Schasinglulu 
187*91f16700Schasinglulu 	/* Caller can be NS-EL2/EL1 */
188*91f16700Schasinglulu 	if (dl_caller_el == MODE_EL3) {
189*91f16700Schasinglulu 		ERROR("DRTM: invalid launch from EL3\n");
190*91f16700Schasinglulu 		return DENIED;
191*91f16700Schasinglulu 	}
192*91f16700Schasinglulu 
193*91f16700Schasinglulu 	if (dl_caller_aarch != MODE_RW_64) {
194*91f16700Schasinglulu 		ERROR("DRTM: invalid launch from non-AArch64 execution state\n");
195*91f16700Schasinglulu 		return DENIED;
196*91f16700Schasinglulu 	}
197*91f16700Schasinglulu 
198*91f16700Schasinglulu 	return SUCCESS;
199*91f16700Schasinglulu }
200*91f16700Schasinglulu 
201*91f16700Schasinglulu static enum drtm_retc drtm_dl_check_cores(void)
202*91f16700Schasinglulu {
203*91f16700Schasinglulu 	bool running_on_single_core;
204*91f16700Schasinglulu 	uint64_t this_pe_aff_value = read_mpidr_el1() & MPIDR_AFFINITY_MASK;
205*91f16700Schasinglulu 
206*91f16700Schasinglulu 	if (this_pe_aff_value != plat_drtm_features.boot_pe_id) {
207*91f16700Schasinglulu 		ERROR("DRTM: invalid launch on a non-boot PE\n");
208*91f16700Schasinglulu 		return DENIED;
209*91f16700Schasinglulu 	}
210*91f16700Schasinglulu 
211*91f16700Schasinglulu 	running_on_single_core = psci_is_last_on_cpu_safe();
212*91f16700Schasinglulu 	if (!running_on_single_core) {
213*91f16700Schasinglulu 		ERROR("DRTM: invalid launch due to non-boot PE not being turned off\n");
214*91f16700Schasinglulu 		return DENIED;
215*91f16700Schasinglulu 	}
216*91f16700Schasinglulu 
217*91f16700Schasinglulu 	return SUCCESS;
218*91f16700Schasinglulu }
219*91f16700Schasinglulu 
220*91f16700Schasinglulu static enum drtm_retc drtm_dl_prepare_dlme_data(const struct_drtm_dl_args *args)
221*91f16700Schasinglulu {
222*91f16700Schasinglulu 	int rc;
223*91f16700Schasinglulu 	uint64_t dlme_data_paddr;
224*91f16700Schasinglulu 	size_t dlme_data_max_size;
225*91f16700Schasinglulu 	uintptr_t dlme_data_mapping;
226*91f16700Schasinglulu 	struct_dlme_data_header *dlme_data_hdr;
227*91f16700Schasinglulu 	uint8_t *dlme_data_cursor;
228*91f16700Schasinglulu 	size_t dlme_data_mapping_bytes;
229*91f16700Schasinglulu 	size_t serialised_bytes_actual;
230*91f16700Schasinglulu 
231*91f16700Schasinglulu 	dlme_data_paddr = args->dlme_paddr + args->dlme_data_off;
232*91f16700Schasinglulu 	dlme_data_max_size = args->dlme_size - args->dlme_data_off;
233*91f16700Schasinglulu 
234*91f16700Schasinglulu 	/*
235*91f16700Schasinglulu 	 * The capacity of the given DLME data region is checked when
236*91f16700Schasinglulu 	 * the other dynamic launch arguments are.
237*91f16700Schasinglulu 	 */
238*91f16700Schasinglulu 	if (dlme_data_max_size < dlme_data_min_size) {
239*91f16700Schasinglulu 		ERROR("%s: assertion failed:"
240*91f16700Schasinglulu 		      " dlme_data_max_size (%ld) < dlme_data_total_bytes_req (%ld)\n",
241*91f16700Schasinglulu 		      __func__, dlme_data_max_size, dlme_data_min_size);
242*91f16700Schasinglulu 		panic();
243*91f16700Schasinglulu 	}
244*91f16700Schasinglulu 
245*91f16700Schasinglulu 	/* Map the DLME data region as NS memory. */
246*91f16700Schasinglulu 	dlme_data_mapping_bytes = ALIGNED_UP(dlme_data_max_size, DRTM_PAGE_SIZE);
247*91f16700Schasinglulu 	rc = mmap_add_dynamic_region_alloc_va(dlme_data_paddr,
248*91f16700Schasinglulu 					      &dlme_data_mapping,
249*91f16700Schasinglulu 					      dlme_data_mapping_bytes,
250*91f16700Schasinglulu 					      MT_RW_DATA | MT_NS |
251*91f16700Schasinglulu 					      MT_SHAREABILITY_ISH);
252*91f16700Schasinglulu 	if (rc != 0) {
253*91f16700Schasinglulu 		WARN("DRTM: %s: mmap_add_dynamic_region() failed rc=%d\n",
254*91f16700Schasinglulu 		     __func__, rc);
255*91f16700Schasinglulu 		return INTERNAL_ERROR;
256*91f16700Schasinglulu 	}
257*91f16700Schasinglulu 	dlme_data_hdr = (struct_dlme_data_header *)dlme_data_mapping;
258*91f16700Schasinglulu 	dlme_data_cursor = (uint8_t *)dlme_data_hdr + sizeof(*dlme_data_hdr);
259*91f16700Schasinglulu 
260*91f16700Schasinglulu 	memcpy(dlme_data_hdr, (const void *)&dlme_data_hdr_init,
261*91f16700Schasinglulu 	       sizeof(*dlme_data_hdr));
262*91f16700Schasinglulu 
263*91f16700Schasinglulu 	/* Set the header version and size. */
264*91f16700Schasinglulu 	dlme_data_hdr->version = 1;
265*91f16700Schasinglulu 	dlme_data_hdr->this_hdr_size = sizeof(*dlme_data_hdr);
266*91f16700Schasinglulu 
267*91f16700Schasinglulu 	/* Prepare DLME protected regions. */
268*91f16700Schasinglulu 	drtm_dma_prot_serialise_table(dlme_data_cursor,
269*91f16700Schasinglulu 				      &serialised_bytes_actual);
270*91f16700Schasinglulu 	assert(serialised_bytes_actual ==
271*91f16700Schasinglulu 	       dlme_data_hdr->dlme_prot_regions_size);
272*91f16700Schasinglulu 	dlme_data_cursor += serialised_bytes_actual;
273*91f16700Schasinglulu 
274*91f16700Schasinglulu 	/* Prepare DLME address map. */
275*91f16700Schasinglulu 	if (plat_drtm_mem_map != NULL) {
276*91f16700Schasinglulu 		memcpy(dlme_data_cursor, plat_drtm_mem_map,
277*91f16700Schasinglulu 		       dlme_data_hdr->dlme_addr_map_size);
278*91f16700Schasinglulu 	} else {
279*91f16700Schasinglulu 		WARN("DRTM: DLME address map is not in the cache\n");
280*91f16700Schasinglulu 	}
281*91f16700Schasinglulu 	dlme_data_cursor += dlme_data_hdr->dlme_addr_map_size;
282*91f16700Schasinglulu 
283*91f16700Schasinglulu 	/* Prepare DRTM event log for DLME. */
284*91f16700Schasinglulu 	drtm_serialise_event_log(dlme_data_cursor, &serialised_bytes_actual);
285*91f16700Schasinglulu 	assert(serialised_bytes_actual <= PLAT_DRTM_EVENT_LOG_MAX_SIZE);
286*91f16700Schasinglulu 	dlme_data_hdr->dlme_tpm_log_size = serialised_bytes_actual;
287*91f16700Schasinglulu 	dlme_data_cursor += serialised_bytes_actual;
288*91f16700Schasinglulu 
289*91f16700Schasinglulu 	/*
290*91f16700Schasinglulu 	 * TODO: Prepare the TCB hashes for DLME, currently its size
291*91f16700Schasinglulu 	 * 0
292*91f16700Schasinglulu 	 */
293*91f16700Schasinglulu 	dlme_data_cursor += dlme_data_hdr->dlme_tcb_hashes_table_size;
294*91f16700Schasinglulu 
295*91f16700Schasinglulu 	/* Implementation-specific region size is unused. */
296*91f16700Schasinglulu 	dlme_data_cursor += dlme_data_hdr->dlme_impdef_region_size;
297*91f16700Schasinglulu 
298*91f16700Schasinglulu 	/*
299*91f16700Schasinglulu 	 * Prepare DLME data size, includes all data region referenced above
300*91f16700Schasinglulu 	 * alongwith the DLME data header
301*91f16700Schasinglulu 	 */
302*91f16700Schasinglulu 	dlme_data_hdr->dlme_data_size = dlme_data_cursor - (uint8_t *)dlme_data_hdr;
303*91f16700Schasinglulu 
304*91f16700Schasinglulu 	/* Unmap the DLME data region. */
305*91f16700Schasinglulu 	rc = mmap_remove_dynamic_region(dlme_data_mapping, dlme_data_mapping_bytes);
306*91f16700Schasinglulu 	if (rc != 0) {
307*91f16700Schasinglulu 		ERROR("%s(): mmap_remove_dynamic_region() failed"
308*91f16700Schasinglulu 		      " unexpectedly rc=%d\n", __func__, rc);
309*91f16700Schasinglulu 		panic();
310*91f16700Schasinglulu 	}
311*91f16700Schasinglulu 
312*91f16700Schasinglulu 	return SUCCESS;
313*91f16700Schasinglulu }
314*91f16700Schasinglulu 
315*91f16700Schasinglulu /*
316*91f16700Schasinglulu  * Note: accesses to the dynamic launch args, and to the DLME data are
317*91f16700Schasinglulu  * little-endian as required, thanks to TF-A BL31 init requirements.
318*91f16700Schasinglulu  */
319*91f16700Schasinglulu static enum drtm_retc drtm_dl_check_args(uint64_t x1,
320*91f16700Schasinglulu 					 struct_drtm_dl_args *a_out)
321*91f16700Schasinglulu {
322*91f16700Schasinglulu 	uint64_t dlme_start, dlme_end;
323*91f16700Schasinglulu 	uint64_t dlme_img_start, dlme_img_ep, dlme_img_end;
324*91f16700Schasinglulu 	uint64_t dlme_data_start, dlme_data_end;
325*91f16700Schasinglulu 	uintptr_t va_mapping;
326*91f16700Schasinglulu 	size_t va_mapping_size;
327*91f16700Schasinglulu 	struct_drtm_dl_args *a;
328*91f16700Schasinglulu 	struct_drtm_dl_args args_buf;
329*91f16700Schasinglulu 	int rc;
330*91f16700Schasinglulu 
331*91f16700Schasinglulu 	if (x1 % DRTM_PAGE_SIZE != 0) {
332*91f16700Schasinglulu 		ERROR("DRTM: parameters structure is not "
333*91f16700Schasinglulu 		      DRTM_PAGE_SIZE_STR "-aligned\n");
334*91f16700Schasinglulu 		return INVALID_PARAMETERS;
335*91f16700Schasinglulu 	}
336*91f16700Schasinglulu 
337*91f16700Schasinglulu 	va_mapping_size = ALIGNED_UP(sizeof(struct_drtm_dl_args), DRTM_PAGE_SIZE);
338*91f16700Schasinglulu 
339*91f16700Schasinglulu 	/* check DRTM parameters are within NS address region */
340*91f16700Schasinglulu 	rc = plat_drtm_validate_ns_region(x1, va_mapping_size);
341*91f16700Schasinglulu 	if (rc != 0) {
342*91f16700Schasinglulu 		ERROR("DRTM: parameters lies within secure memory\n");
343*91f16700Schasinglulu 		return INVALID_PARAMETERS;
344*91f16700Schasinglulu 	}
345*91f16700Schasinglulu 
346*91f16700Schasinglulu 	rc = mmap_add_dynamic_region_alloc_va(x1, &va_mapping, va_mapping_size,
347*91f16700Schasinglulu 					      MT_MEMORY | MT_NS | MT_RO |
348*91f16700Schasinglulu 					      MT_SHAREABILITY_ISH);
349*91f16700Schasinglulu 	if (rc != 0) {
350*91f16700Schasinglulu 		WARN("DRTM: %s: mmap_add_dynamic_region() failed rc=%d\n",
351*91f16700Schasinglulu 		      __func__, rc);
352*91f16700Schasinglulu 		return INTERNAL_ERROR;
353*91f16700Schasinglulu 	}
354*91f16700Schasinglulu 	a = (struct_drtm_dl_args *)va_mapping;
355*91f16700Schasinglulu 
356*91f16700Schasinglulu 	/* Sanitize cache of data passed in args by the DCE Preamble. */
357*91f16700Schasinglulu 	flush_dcache_range(va_mapping, va_mapping_size);
358*91f16700Schasinglulu 
359*91f16700Schasinglulu 	args_buf = *a;
360*91f16700Schasinglulu 
361*91f16700Schasinglulu 	rc = mmap_remove_dynamic_region(va_mapping, va_mapping_size);
362*91f16700Schasinglulu 	if (rc) {
363*91f16700Schasinglulu 		ERROR("%s(): mmap_remove_dynamic_region() failed unexpectedly"
364*91f16700Schasinglulu 		      " rc=%d\n", __func__, rc);
365*91f16700Schasinglulu 		panic();
366*91f16700Schasinglulu 	}
367*91f16700Schasinglulu 	a = &args_buf;
368*91f16700Schasinglulu 
369*91f16700Schasinglulu 	if (!((a->version >= ARM_DRTM_PARAMS_MIN_VERSION) &&
370*91f16700Schasinglulu 	    (a->version <= ARM_DRTM_PARAMS_MAX_VERSION))) {
371*91f16700Schasinglulu 		ERROR("DRTM: parameters structure version %u is unsupported\n",
372*91f16700Schasinglulu 		      a->version);
373*91f16700Schasinglulu 		return NOT_SUPPORTED;
374*91f16700Schasinglulu 	}
375*91f16700Schasinglulu 
376*91f16700Schasinglulu 	if (!(a->dlme_img_off < a->dlme_size &&
377*91f16700Schasinglulu 	      a->dlme_data_off < a->dlme_size)) {
378*91f16700Schasinglulu 		ERROR("DRTM: argument offset is outside of the DLME region\n");
379*91f16700Schasinglulu 		return INVALID_PARAMETERS;
380*91f16700Schasinglulu 	}
381*91f16700Schasinglulu 	dlme_start = a->dlme_paddr;
382*91f16700Schasinglulu 	dlme_end = a->dlme_paddr + a->dlme_size;
383*91f16700Schasinglulu 	dlme_img_start = a->dlme_paddr + a->dlme_img_off;
384*91f16700Schasinglulu 	dlme_img_ep = dlme_img_start + a->dlme_img_ep_off;
385*91f16700Schasinglulu 	dlme_img_end = dlme_img_start + a->dlme_img_size;
386*91f16700Schasinglulu 	dlme_data_start = a->dlme_paddr + a->dlme_data_off;
387*91f16700Schasinglulu 	dlme_data_end = dlme_end;
388*91f16700Schasinglulu 
389*91f16700Schasinglulu 	/* Check the DLME regions arguments. */
390*91f16700Schasinglulu 	if ((dlme_start % DRTM_PAGE_SIZE) != 0) {
391*91f16700Schasinglulu 		ERROR("DRTM: argument DLME region is not "
392*91f16700Schasinglulu 		      DRTM_PAGE_SIZE_STR "-aligned\n");
393*91f16700Schasinglulu 		return INVALID_PARAMETERS;
394*91f16700Schasinglulu 	}
395*91f16700Schasinglulu 
396*91f16700Schasinglulu 	if (!(dlme_start < dlme_end &&
397*91f16700Schasinglulu 	      dlme_start <= dlme_img_start && dlme_img_start < dlme_img_end &&
398*91f16700Schasinglulu 	      dlme_start <= dlme_data_start && dlme_data_start < dlme_data_end)) {
399*91f16700Schasinglulu 		ERROR("DRTM: argument DLME region is discontiguous\n");
400*91f16700Schasinglulu 		return INVALID_PARAMETERS;
401*91f16700Schasinglulu 	}
402*91f16700Schasinglulu 
403*91f16700Schasinglulu 	if (dlme_img_start < dlme_data_end && dlme_data_start < dlme_img_end) {
404*91f16700Schasinglulu 		ERROR("DRTM: argument DLME regions overlap\n");
405*91f16700Schasinglulu 		return INVALID_PARAMETERS;
406*91f16700Schasinglulu 	}
407*91f16700Schasinglulu 
408*91f16700Schasinglulu 	/* Check the DLME image region arguments. */
409*91f16700Schasinglulu 	if ((dlme_img_start % DRTM_PAGE_SIZE) != 0) {
410*91f16700Schasinglulu 		ERROR("DRTM: argument DLME image region is not "
411*91f16700Schasinglulu 		      DRTM_PAGE_SIZE_STR "-aligned\n");
412*91f16700Schasinglulu 		return INVALID_PARAMETERS;
413*91f16700Schasinglulu 	}
414*91f16700Schasinglulu 
415*91f16700Schasinglulu 	if (!(dlme_img_start <= dlme_img_ep && dlme_img_ep < dlme_img_end)) {
416*91f16700Schasinglulu 		ERROR("DRTM: DLME entry point is outside of the DLME image region\n");
417*91f16700Schasinglulu 		return INVALID_PARAMETERS;
418*91f16700Schasinglulu 	}
419*91f16700Schasinglulu 
420*91f16700Schasinglulu 	if ((dlme_img_ep % 4) != 0) {
421*91f16700Schasinglulu 		ERROR("DRTM: DLME image entry point is not 4-byte-aligned\n");
422*91f16700Schasinglulu 		return INVALID_PARAMETERS;
423*91f16700Schasinglulu 	}
424*91f16700Schasinglulu 
425*91f16700Schasinglulu 	/* Check the DLME data region arguments. */
426*91f16700Schasinglulu 	if ((dlme_data_start % DRTM_PAGE_SIZE) != 0) {
427*91f16700Schasinglulu 		ERROR("DRTM: argument DLME data region is not "
428*91f16700Schasinglulu 		      DRTM_PAGE_SIZE_STR "-aligned\n");
429*91f16700Schasinglulu 		return INVALID_PARAMETERS;
430*91f16700Schasinglulu 	}
431*91f16700Schasinglulu 
432*91f16700Schasinglulu 	if (dlme_data_end - dlme_data_start < dlme_data_min_size) {
433*91f16700Schasinglulu 		ERROR("DRTM: argument DLME data region is short of %lu bytes\n",
434*91f16700Schasinglulu 		      dlme_data_min_size - (size_t)(dlme_data_end - dlme_data_start));
435*91f16700Schasinglulu 		return INVALID_PARAMETERS;
436*91f16700Schasinglulu 	}
437*91f16700Schasinglulu 
438*91f16700Schasinglulu 	/* check DLME region (paddr + size) is within a NS address region */
439*91f16700Schasinglulu 	rc = plat_drtm_validate_ns_region(dlme_start, (size_t)a->dlme_size);
440*91f16700Schasinglulu 	if (rc != 0) {
441*91f16700Schasinglulu 		ERROR("DRTM: DLME region lies within secure memory\n");
442*91f16700Schasinglulu 		return INVALID_PARAMETERS;
443*91f16700Schasinglulu 	}
444*91f16700Schasinglulu 
445*91f16700Schasinglulu 	/* Check the Normal World DCE region arguments. */
446*91f16700Schasinglulu 	if (a->dce_nwd_paddr != 0) {
447*91f16700Schasinglulu 		uint32_t dce_nwd_start = a->dce_nwd_paddr;
448*91f16700Schasinglulu 		uint32_t dce_nwd_end = dce_nwd_start + a->dce_nwd_size;
449*91f16700Schasinglulu 
450*91f16700Schasinglulu 		if (!(dce_nwd_start < dce_nwd_end)) {
451*91f16700Schasinglulu 			ERROR("DRTM: argument Normal World DCE region is dicontiguous\n");
452*91f16700Schasinglulu 			return INVALID_PARAMETERS;
453*91f16700Schasinglulu 		}
454*91f16700Schasinglulu 
455*91f16700Schasinglulu 		if (dce_nwd_start < dlme_end && dlme_start < dce_nwd_end) {
456*91f16700Schasinglulu 			ERROR("DRTM: argument Normal World DCE regions overlap\n");
457*91f16700Schasinglulu 			return INVALID_PARAMETERS;
458*91f16700Schasinglulu 		}
459*91f16700Schasinglulu 	}
460*91f16700Schasinglulu 
461*91f16700Schasinglulu 	/*
462*91f16700Schasinglulu 	 * Map and sanitize the cache of data range passed by DCE Preamble. This
463*91f16700Schasinglulu 	 * is required to avoid / defend against racing with cache evictions
464*91f16700Schasinglulu 	 */
465*91f16700Schasinglulu 	va_mapping_size = ALIGNED_UP((dlme_end - dlme_start), DRTM_PAGE_SIZE);
466*91f16700Schasinglulu 	rc = mmap_add_dynamic_region_alloc_va(dlme_img_start, &va_mapping, va_mapping_size,
467*91f16700Schasinglulu 					      MT_MEMORY | MT_NS | MT_RO |
468*91f16700Schasinglulu 					      MT_SHAREABILITY_ISH);
469*91f16700Schasinglulu 	if (rc != 0) {
470*91f16700Schasinglulu 		ERROR("DRTM: %s: mmap_add_dynamic_region_alloc_va() failed rc=%d\n",
471*91f16700Schasinglulu 		      __func__, rc);
472*91f16700Schasinglulu 		return INTERNAL_ERROR;
473*91f16700Schasinglulu 	}
474*91f16700Schasinglulu 	flush_dcache_range(va_mapping, va_mapping_size);
475*91f16700Schasinglulu 
476*91f16700Schasinglulu 	rc = mmap_remove_dynamic_region(va_mapping, va_mapping_size);
477*91f16700Schasinglulu 	if (rc) {
478*91f16700Schasinglulu 		ERROR("%s(): mmap_remove_dynamic_region() failed unexpectedly"
479*91f16700Schasinglulu 		      " rc=%d\n", __func__, rc);
480*91f16700Schasinglulu 		panic();
481*91f16700Schasinglulu 	}
482*91f16700Schasinglulu 
483*91f16700Schasinglulu 	*a_out = *a;
484*91f16700Schasinglulu 	return SUCCESS;
485*91f16700Schasinglulu }
486*91f16700Schasinglulu 
487*91f16700Schasinglulu static void drtm_dl_reset_dlme_el_state(enum drtm_dlme_el dlme_el)
488*91f16700Schasinglulu {
489*91f16700Schasinglulu 	uint64_t sctlr;
490*91f16700Schasinglulu 
491*91f16700Schasinglulu 	/*
492*91f16700Schasinglulu 	 * TODO: Set PE state according to the PSCI's specification of the initial
493*91f16700Schasinglulu 	 * state after CPU_ON, or to reset values if unspecified, where they exist,
494*91f16700Schasinglulu 	 * or define sensible values otherwise.
495*91f16700Schasinglulu 	 */
496*91f16700Schasinglulu 
497*91f16700Schasinglulu 	switch (dlme_el) {
498*91f16700Schasinglulu 	case DLME_AT_EL1:
499*91f16700Schasinglulu 		sctlr = read_sctlr_el1();
500*91f16700Schasinglulu 		break;
501*91f16700Schasinglulu 
502*91f16700Schasinglulu 	case DLME_AT_EL2:
503*91f16700Schasinglulu 		sctlr = read_sctlr_el2();
504*91f16700Schasinglulu 		break;
505*91f16700Schasinglulu 
506*91f16700Schasinglulu 	default: /* Not reached */
507*91f16700Schasinglulu 		ERROR("%s(): dlme_el has the unexpected value %d\n",
508*91f16700Schasinglulu 		      __func__, dlme_el);
509*91f16700Schasinglulu 		panic();
510*91f16700Schasinglulu 	}
511*91f16700Schasinglulu 
512*91f16700Schasinglulu 	sctlr &= ~(/* Disable DLME's EL MMU, since the existing page-tables are untrusted. */
513*91f16700Schasinglulu 		   SCTLR_M_BIT
514*91f16700Schasinglulu 		   | SCTLR_EE_BIT               /* Little-endian data accesses. */
515*91f16700Schasinglulu 		  );
516*91f16700Schasinglulu 
517*91f16700Schasinglulu 	sctlr |= SCTLR_C_BIT | SCTLR_I_BIT; /* Allow instruction and data caching. */
518*91f16700Schasinglulu 
519*91f16700Schasinglulu 	switch (dlme_el) {
520*91f16700Schasinglulu 	case DLME_AT_EL1:
521*91f16700Schasinglulu 		write_sctlr_el1(sctlr);
522*91f16700Schasinglulu 		break;
523*91f16700Schasinglulu 
524*91f16700Schasinglulu 	case DLME_AT_EL2:
525*91f16700Schasinglulu 		write_sctlr_el2(sctlr);
526*91f16700Schasinglulu 		break;
527*91f16700Schasinglulu 	}
528*91f16700Schasinglulu }
529*91f16700Schasinglulu 
530*91f16700Schasinglulu static void drtm_dl_reset_dlme_context(enum drtm_dlme_el dlme_el)
531*91f16700Schasinglulu {
532*91f16700Schasinglulu 	void *ns_ctx = cm_get_context(NON_SECURE);
533*91f16700Schasinglulu 	gp_regs_t *gpregs = get_gpregs_ctx(ns_ctx);
534*91f16700Schasinglulu 	uint64_t spsr_el3 = read_ctx_reg(get_el3state_ctx(ns_ctx), CTX_SPSR_EL3);
535*91f16700Schasinglulu 
536*91f16700Schasinglulu 	/* Reset all gpregs, including SP_EL0. */
537*91f16700Schasinglulu 	memset(gpregs, 0, sizeof(*gpregs));
538*91f16700Schasinglulu 
539*91f16700Schasinglulu 	/* Reset SP_ELx. */
540*91f16700Schasinglulu 	switch (dlme_el) {
541*91f16700Schasinglulu 	case DLME_AT_EL1:
542*91f16700Schasinglulu 		write_sp_el1(0);
543*91f16700Schasinglulu 		break;
544*91f16700Schasinglulu 
545*91f16700Schasinglulu 	case DLME_AT_EL2:
546*91f16700Schasinglulu 		write_sp_el2(0);
547*91f16700Schasinglulu 		break;
548*91f16700Schasinglulu 	}
549*91f16700Schasinglulu 
550*91f16700Schasinglulu 	/*
551*91f16700Schasinglulu 	 * DLME's async exceptions are masked to avoid a NWd attacker's timed
552*91f16700Schasinglulu 	 * interference with any state we established trust in or measured.
553*91f16700Schasinglulu 	 */
554*91f16700Schasinglulu 	spsr_el3 |= SPSR_DAIF_MASK << SPSR_DAIF_SHIFT;
555*91f16700Schasinglulu 
556*91f16700Schasinglulu 	write_ctx_reg(get_el3state_ctx(ns_ctx), CTX_SPSR_EL3, spsr_el3);
557*91f16700Schasinglulu }
558*91f16700Schasinglulu 
559*91f16700Schasinglulu static void drtm_dl_prepare_eret_to_dlme(const struct_drtm_dl_args *args, enum drtm_dlme_el dlme_el)
560*91f16700Schasinglulu {
561*91f16700Schasinglulu 	void *ctx = cm_get_context(NON_SECURE);
562*91f16700Schasinglulu 	uint64_t dlme_ep = DL_ARGS_GET_DLME_ENTRY_POINT(args);
563*91f16700Schasinglulu 	uint64_t spsr_el3 = read_ctx_reg(get_el3state_ctx(ctx), CTX_SPSR_EL3);
564*91f16700Schasinglulu 
565*91f16700Schasinglulu 	/* Next ERET is to the DLME's EL. */
566*91f16700Schasinglulu 	spsr_el3 &= ~(MODE_EL_MASK << MODE_EL_SHIFT);
567*91f16700Schasinglulu 	switch (dlme_el) {
568*91f16700Schasinglulu 	case DLME_AT_EL1:
569*91f16700Schasinglulu 		spsr_el3 |= MODE_EL1 << MODE_EL_SHIFT;
570*91f16700Schasinglulu 		break;
571*91f16700Schasinglulu 
572*91f16700Schasinglulu 	case DLME_AT_EL2:
573*91f16700Schasinglulu 		spsr_el3 |= MODE_EL2 << MODE_EL_SHIFT;
574*91f16700Schasinglulu 		break;
575*91f16700Schasinglulu 	}
576*91f16700Schasinglulu 
577*91f16700Schasinglulu 	/* Next ERET is to the DLME entry point. */
578*91f16700Schasinglulu 	cm_set_elr_spsr_el3(NON_SECURE, dlme_ep, spsr_el3);
579*91f16700Schasinglulu }
580*91f16700Schasinglulu 
581*91f16700Schasinglulu static uint64_t drtm_dynamic_launch(uint64_t x1, void *handle)
582*91f16700Schasinglulu {
583*91f16700Schasinglulu 	enum drtm_retc ret = SUCCESS;
584*91f16700Schasinglulu 	enum drtm_retc dma_prot_ret;
585*91f16700Schasinglulu 	struct_drtm_dl_args args;
586*91f16700Schasinglulu 	/* DLME should be highest NS exception level */
587*91f16700Schasinglulu 	enum drtm_dlme_el dlme_el = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1;
588*91f16700Schasinglulu 
589*91f16700Schasinglulu 	/* Ensure that only boot PE is powered on */
590*91f16700Schasinglulu 	ret = drtm_dl_check_cores();
591*91f16700Schasinglulu 	if (ret != SUCCESS) {
592*91f16700Schasinglulu 		SMC_RET1(handle, ret);
593*91f16700Schasinglulu 	}
594*91f16700Schasinglulu 
595*91f16700Schasinglulu 	/*
596*91f16700Schasinglulu 	 * Ensure that execution state is AArch64 and the caller
597*91f16700Schasinglulu 	 * is highest non-secure exception level
598*91f16700Schasinglulu 	 */
599*91f16700Schasinglulu 	ret = drtm_dl_check_caller_el(handle);
600*91f16700Schasinglulu 	if (ret != SUCCESS) {
601*91f16700Schasinglulu 		SMC_RET1(handle, ret);
602*91f16700Schasinglulu 	}
603*91f16700Schasinglulu 
604*91f16700Schasinglulu 	ret = drtm_dl_check_args(x1, &args);
605*91f16700Schasinglulu 	if (ret != SUCCESS) {
606*91f16700Schasinglulu 		SMC_RET1(handle, ret);
607*91f16700Schasinglulu 	}
608*91f16700Schasinglulu 
609*91f16700Schasinglulu 	/* Ensure that there are no SDEI event registered */
610*91f16700Schasinglulu #if SDEI_SUPPORT
611*91f16700Schasinglulu 	if (sdei_get_registered_event_count() != 0) {
612*91f16700Schasinglulu 		SMC_RET1(handle, DENIED);
613*91f16700Schasinglulu 	}
614*91f16700Schasinglulu #endif /* SDEI_SUPPORT */
615*91f16700Schasinglulu 
616*91f16700Schasinglulu 	/*
617*91f16700Schasinglulu 	 * Engage the DMA protections.  The launch cannot proceed without the DMA
618*91f16700Schasinglulu 	 * protections due to potential TOC/TOU vulnerabilities w.r.t. the DLME
619*91f16700Schasinglulu 	 * region (and to the NWd DCE region).
620*91f16700Schasinglulu 	 */
621*91f16700Schasinglulu 	ret = drtm_dma_prot_engage(&args.dma_prot_args,
622*91f16700Schasinglulu 				   DL_ARGS_GET_DMA_PROT_TYPE(&args));
623*91f16700Schasinglulu 	if (ret != SUCCESS) {
624*91f16700Schasinglulu 		SMC_RET1(handle, ret);
625*91f16700Schasinglulu 	}
626*91f16700Schasinglulu 
627*91f16700Schasinglulu 	/*
628*91f16700Schasinglulu 	 * The DMA protection is now engaged.  Note that any failure mode that
629*91f16700Schasinglulu 	 * returns an error to the DRTM-launch caller must now disengage DMA
630*91f16700Schasinglulu 	 * protections before returning to the caller.
631*91f16700Schasinglulu 	 */
632*91f16700Schasinglulu 
633*91f16700Schasinglulu 	ret = drtm_take_measurements(&args);
634*91f16700Schasinglulu 	if (ret != SUCCESS) {
635*91f16700Schasinglulu 		goto err_undo_dma_prot;
636*91f16700Schasinglulu 	}
637*91f16700Schasinglulu 
638*91f16700Schasinglulu 	ret = drtm_dl_prepare_dlme_data(&args);
639*91f16700Schasinglulu 	if (ret != SUCCESS) {
640*91f16700Schasinglulu 		goto err_undo_dma_prot;
641*91f16700Schasinglulu 	}
642*91f16700Schasinglulu 
643*91f16700Schasinglulu 	/*
644*91f16700Schasinglulu 	 * Note that, at the time of writing, the DRTM spec allows a successful
645*91f16700Schasinglulu 	 * launch from NS-EL1 to return to a DLME in NS-EL2.  The practical risk
646*91f16700Schasinglulu 	 * of a privilege escalation, e.g. due to a compromised hypervisor, is
647*91f16700Schasinglulu 	 * considered small enough not to warrant the specification of additional
648*91f16700Schasinglulu 	 * DRTM conduits that would be necessary to maintain OSs' abstraction from
649*91f16700Schasinglulu 	 * the presence of EL2 were the dynamic launch only be allowed from the
650*91f16700Schasinglulu 	 * highest NS EL.
651*91f16700Schasinglulu 	 */
652*91f16700Schasinglulu 
653*91f16700Schasinglulu 	dlme_el = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1;
654*91f16700Schasinglulu 
655*91f16700Schasinglulu 	drtm_dl_reset_dlme_el_state(dlme_el);
656*91f16700Schasinglulu 	drtm_dl_reset_dlme_context(dlme_el);
657*91f16700Schasinglulu 
658*91f16700Schasinglulu 	drtm_dl_prepare_eret_to_dlme(&args, dlme_el);
659*91f16700Schasinglulu 
660*91f16700Schasinglulu 	/*
661*91f16700Schasinglulu 	 * As per DRTM beta0 spec table #28 invalidate the instruction cache
662*91f16700Schasinglulu 	 * before jumping to the DLME. This is required to defend against
663*91f16700Schasinglulu 	 * potentially-malicious cache contents.
664*91f16700Schasinglulu 	 */
665*91f16700Schasinglulu 	invalidate_icache_all();
666*91f16700Schasinglulu 
667*91f16700Schasinglulu 	/* Return the DLME region's address in x0, and the DLME data offset in x1.*/
668*91f16700Schasinglulu 	SMC_RET2(handle, args.dlme_paddr, args.dlme_data_off);
669*91f16700Schasinglulu 
670*91f16700Schasinglulu err_undo_dma_prot:
671*91f16700Schasinglulu 	dma_prot_ret = drtm_dma_prot_disengage();
672*91f16700Schasinglulu 	if (dma_prot_ret != SUCCESS) {
673*91f16700Schasinglulu 		ERROR("%s(): drtm_dma_prot_disengage() failed unexpectedly"
674*91f16700Schasinglulu 		      " rc=%d\n", __func__, ret);
675*91f16700Schasinglulu 		panic();
676*91f16700Schasinglulu 	}
677*91f16700Schasinglulu 
678*91f16700Schasinglulu 	SMC_RET1(handle, ret);
679*91f16700Schasinglulu }
680*91f16700Schasinglulu 
681*91f16700Schasinglulu uint64_t drtm_smc_handler(uint32_t smc_fid,
682*91f16700Schasinglulu 			  uint64_t x1,
683*91f16700Schasinglulu 			  uint64_t x2,
684*91f16700Schasinglulu 			  uint64_t x3,
685*91f16700Schasinglulu 			  uint64_t x4,
686*91f16700Schasinglulu 			  void *cookie,
687*91f16700Schasinglulu 			  void *handle,
688*91f16700Schasinglulu 			  uint64_t flags)
689*91f16700Schasinglulu {
690*91f16700Schasinglulu 	/* Check that the SMC call is from the Normal World. */
691*91f16700Schasinglulu 	if (!is_caller_non_secure(flags)) {
692*91f16700Schasinglulu 		SMC_RET1(handle, NOT_SUPPORTED);
693*91f16700Schasinglulu 	}
694*91f16700Schasinglulu 
695*91f16700Schasinglulu 	switch (smc_fid) {
696*91f16700Schasinglulu 	case ARM_DRTM_SVC_VERSION:
697*91f16700Schasinglulu 		INFO("DRTM service handler: version\n");
698*91f16700Schasinglulu 		/* Return the version of current implementation */
699*91f16700Schasinglulu 		SMC_RET1(handle, ARM_DRTM_VERSION);
700*91f16700Schasinglulu 		break;	/* not reached */
701*91f16700Schasinglulu 
702*91f16700Schasinglulu 	case ARM_DRTM_SVC_FEATURES:
703*91f16700Schasinglulu 		if (((x1 >> ARM_DRTM_FUNC_SHIFT) & ARM_DRTM_FUNC_MASK) ==
704*91f16700Schasinglulu 		    ARM_DRTM_FUNC_ID) {
705*91f16700Schasinglulu 			/* Dispatch function-based queries. */
706*91f16700Schasinglulu 			switch (x1 & FUNCID_MASK) {
707*91f16700Schasinglulu 			case ARM_DRTM_SVC_VERSION:
708*91f16700Schasinglulu 				SMC_RET1(handle, SUCCESS);
709*91f16700Schasinglulu 				break;	/* not reached */
710*91f16700Schasinglulu 
711*91f16700Schasinglulu 			case ARM_DRTM_SVC_FEATURES:
712*91f16700Schasinglulu 				SMC_RET1(handle, SUCCESS);
713*91f16700Schasinglulu 				break;	/* not reached */
714*91f16700Schasinglulu 
715*91f16700Schasinglulu 			case ARM_DRTM_SVC_UNPROTECT_MEM:
716*91f16700Schasinglulu 				SMC_RET1(handle, SUCCESS);
717*91f16700Schasinglulu 				break;	/* not reached */
718*91f16700Schasinglulu 
719*91f16700Schasinglulu 			case ARM_DRTM_SVC_DYNAMIC_LAUNCH:
720*91f16700Schasinglulu 				SMC_RET1(handle, SUCCESS);
721*91f16700Schasinglulu 				break;	/* not reached */
722*91f16700Schasinglulu 
723*91f16700Schasinglulu 			case ARM_DRTM_SVC_CLOSE_LOCALITY:
724*91f16700Schasinglulu 				WARN("ARM_DRTM_SVC_CLOSE_LOCALITY feature %s",
725*91f16700Schasinglulu 				     "is not supported\n");
726*91f16700Schasinglulu 				SMC_RET1(handle, NOT_SUPPORTED);
727*91f16700Schasinglulu 				break;	/* not reached */
728*91f16700Schasinglulu 
729*91f16700Schasinglulu 			case ARM_DRTM_SVC_GET_ERROR:
730*91f16700Schasinglulu 				SMC_RET1(handle, SUCCESS);
731*91f16700Schasinglulu 				break;	/* not reached */
732*91f16700Schasinglulu 
733*91f16700Schasinglulu 			case ARM_DRTM_SVC_SET_ERROR:
734*91f16700Schasinglulu 				SMC_RET1(handle, SUCCESS);
735*91f16700Schasinglulu 				break;	/* not reached */
736*91f16700Schasinglulu 
737*91f16700Schasinglulu 			case ARM_DRTM_SVC_SET_TCB_HASH:
738*91f16700Schasinglulu 				WARN("ARM_DRTM_SVC_TCB_HASH feature %s",
739*91f16700Schasinglulu 				     "is not supported\n");
740*91f16700Schasinglulu 				SMC_RET1(handle, NOT_SUPPORTED);
741*91f16700Schasinglulu 				break;	/* not reached */
742*91f16700Schasinglulu 
743*91f16700Schasinglulu 			case ARM_DRTM_SVC_LOCK_TCB_HASH:
744*91f16700Schasinglulu 				WARN("ARM_DRTM_SVC_LOCK_TCB_HASH feature %s",
745*91f16700Schasinglulu 				     "is not supported\n");
746*91f16700Schasinglulu 				SMC_RET1(handle, NOT_SUPPORTED);
747*91f16700Schasinglulu 				break;	/* not reached */
748*91f16700Schasinglulu 
749*91f16700Schasinglulu 			default:
750*91f16700Schasinglulu 				ERROR("Unknown DRTM service function\n");
751*91f16700Schasinglulu 				SMC_RET1(handle, NOT_SUPPORTED);
752*91f16700Schasinglulu 				break;	/* not reached */
753*91f16700Schasinglulu 			}
754*91f16700Schasinglulu 		} else {
755*91f16700Schasinglulu 			/* Dispatch feature-based queries. */
756*91f16700Schasinglulu 			switch (x1 & ARM_DRTM_FEAT_ID_MASK) {
757*91f16700Schasinglulu 			case ARM_DRTM_FEATURES_TPM:
758*91f16700Schasinglulu 				INFO("++ DRTM service handler: TPM features\n");
759*91f16700Schasinglulu 				return drtm_features_tpm(handle);
760*91f16700Schasinglulu 				break;	/* not reached */
761*91f16700Schasinglulu 
762*91f16700Schasinglulu 			case ARM_DRTM_FEATURES_MEM_REQ:
763*91f16700Schasinglulu 				INFO("++ DRTM service handler: Min. mem."
764*91f16700Schasinglulu 				     " requirement features\n");
765*91f16700Schasinglulu 				return drtm_features_mem_req(handle);
766*91f16700Schasinglulu 				break;	/* not reached */
767*91f16700Schasinglulu 
768*91f16700Schasinglulu 			case ARM_DRTM_FEATURES_DMA_PROT:
769*91f16700Schasinglulu 				INFO("++ DRTM service handler: "
770*91f16700Schasinglulu 				     "DMA protection features\n");
771*91f16700Schasinglulu 				return drtm_features_dma_prot(handle);
772*91f16700Schasinglulu 				break;	/* not reached */
773*91f16700Schasinglulu 
774*91f16700Schasinglulu 			case ARM_DRTM_FEATURES_BOOT_PE_ID:
775*91f16700Schasinglulu 				INFO("++ DRTM service handler: "
776*91f16700Schasinglulu 				     "Boot PE ID features\n");
777*91f16700Schasinglulu 				return drtm_features_boot_pe_id(handle);
778*91f16700Schasinglulu 				break;	/* not reached */
779*91f16700Schasinglulu 
780*91f16700Schasinglulu 			case ARM_DRTM_FEATURES_TCB_HASHES:
781*91f16700Schasinglulu 				INFO("++ DRTM service handler: "
782*91f16700Schasinglulu 				     "TCB-hashes features\n");
783*91f16700Schasinglulu 				return drtm_features_tcb_hashes(handle);
784*91f16700Schasinglulu 				break;	/* not reached */
785*91f16700Schasinglulu 
786*91f16700Schasinglulu 			default:
787*91f16700Schasinglulu 				ERROR("Unknown ARM DRTM service feature\n");
788*91f16700Schasinglulu 				SMC_RET1(handle, NOT_SUPPORTED);
789*91f16700Schasinglulu 				break;	/* not reached */
790*91f16700Schasinglulu 			}
791*91f16700Schasinglulu 		}
792*91f16700Schasinglulu 
793*91f16700Schasinglulu 	case ARM_DRTM_SVC_UNPROTECT_MEM:
794*91f16700Schasinglulu 		INFO("DRTM service handler: unprotect mem\n");
795*91f16700Schasinglulu 		return drtm_unprotect_mem(handle);
796*91f16700Schasinglulu 		break;	/* not reached */
797*91f16700Schasinglulu 
798*91f16700Schasinglulu 	case ARM_DRTM_SVC_DYNAMIC_LAUNCH:
799*91f16700Schasinglulu 		INFO("DRTM service handler: dynamic launch\n");
800*91f16700Schasinglulu 		return drtm_dynamic_launch(x1, handle);
801*91f16700Schasinglulu 		break;	/* not reached */
802*91f16700Schasinglulu 
803*91f16700Schasinglulu 	case ARM_DRTM_SVC_CLOSE_LOCALITY:
804*91f16700Schasinglulu 		WARN("DRTM service handler: close locality %s\n",
805*91f16700Schasinglulu 		     "is not supported");
806*91f16700Schasinglulu 		SMC_RET1(handle, NOT_SUPPORTED);
807*91f16700Schasinglulu 		break;	/* not reached */
808*91f16700Schasinglulu 
809*91f16700Schasinglulu 	case ARM_DRTM_SVC_GET_ERROR:
810*91f16700Schasinglulu 		INFO("DRTM service handler: get error\n");
811*91f16700Schasinglulu 		drtm_get_error(handle);
812*91f16700Schasinglulu 		break;	/* not reached */
813*91f16700Schasinglulu 
814*91f16700Schasinglulu 	case ARM_DRTM_SVC_SET_ERROR:
815*91f16700Schasinglulu 		INFO("DRTM service handler: set error\n");
816*91f16700Schasinglulu 		drtm_set_error(x1, handle);
817*91f16700Schasinglulu 		break;	/* not reached */
818*91f16700Schasinglulu 
819*91f16700Schasinglulu 	case ARM_DRTM_SVC_SET_TCB_HASH:
820*91f16700Schasinglulu 		WARN("DRTM service handler: set TCB hash %s\n",
821*91f16700Schasinglulu 		     "is not supported");
822*91f16700Schasinglulu 		SMC_RET1(handle, NOT_SUPPORTED);
823*91f16700Schasinglulu 		break;  /* not reached */
824*91f16700Schasinglulu 
825*91f16700Schasinglulu 	case ARM_DRTM_SVC_LOCK_TCB_HASH:
826*91f16700Schasinglulu 		WARN("DRTM service handler: lock TCB hash %s\n",
827*91f16700Schasinglulu 		     "is not supported");
828*91f16700Schasinglulu 		SMC_RET1(handle, NOT_SUPPORTED);
829*91f16700Schasinglulu 		break;  /* not reached */
830*91f16700Schasinglulu 
831*91f16700Schasinglulu 	default:
832*91f16700Schasinglulu 		ERROR("Unknown DRTM service function: 0x%x\n", smc_fid);
833*91f16700Schasinglulu 		SMC_RET1(handle, SMC_UNK);
834*91f16700Schasinglulu 		break;	/* not reached */
835*91f16700Schasinglulu 	}
836*91f16700Schasinglulu 
837*91f16700Schasinglulu 	/* not reached */
838*91f16700Schasinglulu 	SMC_RET1(handle, SMC_UNK);
839*91f16700Schasinglulu }
840