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