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