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