1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright 2022-2023, 2025 NXP 4 */ 5 #include <drivers/imx_mu.h> 6 #include <ele.h> 7 #include <initcall.h> 8 #include <kernel/boot.h> 9 #include <kernel/delay.h> 10 #include <kernel/panic.h> 11 #include <kernel/tee_common_otp.h> 12 #include <memutils.h> 13 #include <mm/core_memprot.h> 14 #include <mm/core_mmu.h> 15 #include <rng_support.h> 16 #include <stdint.h> 17 #include <string_ext.h> 18 #include <tee/cache.h> 19 #include <tee_api_defines.h> 20 #include <trace.h> 21 #include <types_ext.h> 22 #include <utee_types.h> 23 #include <util.h> 24 25 #define ELE_BASE_ADDR MU_BASE 26 #define ELE_BASE_SIZE MU_SIZE 27 28 #define ELE_VERSION_BASELINE 0x06 29 #define ELE_COMMAND_SUCCEED 0xd6 30 #define ELE_COMMAND_FAILED 0x29 31 #define ELE_RESPONSE_TAG 0xe1 32 33 #define ELE_CMD_SESSION_OPEN 0x10 34 #define ELE_CMD_SESSION_CLOSE 0x11 35 #define ELE_CMD_RNG_GET 0xCD 36 #define ELE_CMD_TRNG_STATE 0xA4 37 #define ELE_CMD_GET_INFO 0xDA 38 #define ELE_CMD_DERIVE_KEY 0xA9 39 #define ELE_CMD_SAB_INIT 0x17 40 41 #define IMX_ELE_TRNG_STATUS_READY 0x3 42 43 #define ELE_MU_IRQ 0x0 44 45 #define CACHELINE_SIZE 64 46 47 register_phys_mem_pgdir(MEM_AREA_IO_SEC, MU_BASE, MU_SIZE); 48 49 struct get_info_rsp { 50 uint32_t rsp_code; 51 uint16_t soc_id; 52 uint16_t soc_rev; 53 uint16_t lifecycle; 54 uint8_t sssm_state; 55 uint8_t unused_1; 56 uint32_t uid[4]; 57 uint32_t sha256_rom_patch[8]; 58 uint32_t sha256_firmware[8]; 59 uint32_t oem_srkh[16]; 60 uint8_t trng_state; 61 uint8_t csal_state; 62 uint8_t imem_state; 63 uint8_t unused_2; 64 } __packed; 65 66 struct response_code { 67 uint8_t status; 68 uint8_t rating; 69 uint16_t rating_extension; 70 } __packed; 71 72 /* 73 * Print ELE response status and rating 74 * 75 * @rsp response code structure 76 */ 77 static void print_rsp_code(struct response_code rsp __maybe_unused) 78 { 79 DMSG("Response status %#"PRIx8", rating %#"PRIx8" (ext %#"PRIx16")", 80 rsp.status, rsp.rating, rsp.rating_extension); 81 } 82 83 /* 84 * Print ELE message header 85 * 86 * @hdr message header 87 */ 88 static void print_msg_header(struct imx_mu_msg_header hdr __maybe_unused) 89 { 90 DMSG("Header ver %#"PRIx8", size %"PRId8", tag %#"PRIx8", cmd %#"PRIx8, 91 hdr.version, hdr.size, hdr.tag, hdr.command); 92 } 93 94 /* 95 * Print full ELE message content 96 * 97 * @msg message 98 */ 99 static void dump_message(const struct imx_mu_msg *msg __maybe_unused) 100 { 101 size_t i = 0; 102 size_t size __maybe_unused = msg->header.size; 103 uint32_t *data __maybe_unused = (uint32_t *)msg; 104 105 DMSG("Dump of message %p(%zu)", data, size); 106 for (i = 0; i < size; i++) 107 DMSG("word %zu: %#"PRIx32, i, data[i]); 108 } 109 110 /* 111 * The CRC for the message is computed xor-ing all the words of the message: 112 * the header and all the words except the word storing the CRC. 113 * 114 * @msg MU message to hash 115 */ 116 static uint32_t compute_crc(const struct imx_mu_msg *msg) 117 { 118 uint32_t crc = 0; 119 uint8_t i = 0; 120 uint32_t *payload = (uint32_t *)msg; 121 122 assert(msg); 123 124 for (i = 0; i < msg->header.size - 1; i++) 125 crc ^= payload[i]; 126 127 return crc; 128 } 129 130 void update_crc(struct imx_mu_msg *msg) 131 { 132 assert(msg); 133 /* 134 * The CRC field is the last element of array. The size of the header 135 * is also subtracted from CRC computation. 136 */ 137 msg->data.u32[msg->header.size - 2] = compute_crc(msg); 138 } 139 140 /* 141 * Return the given MU base address, depending on the MMU state. 142 * 143 * @pa MU physical base address 144 * @sz MU size 145 */ 146 static vaddr_t imx_ele_init(paddr_t pa, size_t sz) 147 { 148 static bool is_initialized; 149 vaddr_t va = 0; 150 151 assert(pa && sz); 152 153 if (cpu_mmu_enabled()) 154 va = core_mmu_get_va(pa, MEM_AREA_IO_SEC, sz); 155 else 156 va = (vaddr_t)pa; 157 158 if (!is_initialized) { 159 imx_mu_init(va); 160 is_initialized = true; 161 } 162 163 return va; 164 } 165 166 /* 167 * Extract response codes from the given word 168 * 169 * @word 32 bits word MU response 170 */ 171 static struct response_code get_response_code(uint32_t word) 172 { 173 struct response_code rsp = { 174 .rating_extension = (word & GENMASK_32(31, 16)) >> 16, 175 .rating = (word & GENMASK_32(15, 8)) >> 8, 176 .status = (word & GENMASK_32(7, 0)) >> 0, 177 }; 178 179 return rsp; 180 } 181 182 TEE_Result imx_ele_call(struct imx_mu_msg *msg) 183 { 184 TEE_Result res = TEE_ERROR_GENERIC; 185 struct response_code rsp = { }; 186 vaddr_t va = 0; 187 188 assert(msg); 189 190 if (msg->header.tag != ELE_REQUEST_TAG) { 191 EMSG("Request has invalid tag: %#"PRIx8" instead of %#"PRIx8, 192 msg->header.tag, ELE_REQUEST_TAG); 193 return TEE_ERROR_BAD_PARAMETERS; 194 } 195 196 va = imx_ele_init(ELE_BASE_ADDR, ELE_BASE_SIZE); 197 if (!va) { 198 EMSG("Fail to get base address"); 199 return TEE_ERROR_GENERIC; 200 } 201 202 res = imx_mu_call(va, msg, true); 203 if (res) { 204 EMSG("Failed to transmit message: %#"PRIx32, res); 205 print_msg_header(msg->header); 206 dump_message(msg); 207 return res; 208 } 209 210 rsp = get_response_code(msg->data.u32[0]); 211 212 if (msg->header.tag != ELE_RESPONSE_TAG) { 213 EMSG("Response has invalid tag: %#"PRIx8" instead of %#"PRIx8, 214 msg->header.tag, ELE_RESPONSE_TAG); 215 print_msg_header(msg->header); 216 return TEE_ERROR_GENERIC; 217 } 218 219 if (rsp.status != ELE_COMMAND_SUCCEED) { 220 EMSG("Command has failed"); 221 print_rsp_code(rsp); 222 return TEE_ERROR_GENERIC; 223 } 224 225 /* The rating can be different in success and failing cases */ 226 if (rsp.rating != 0) { 227 EMSG("Command has invalid rating: %#"PRIx8, rsp.rating); 228 print_rsp_code(rsp); 229 return TEE_ERROR_GENERIC; 230 } 231 232 return TEE_SUCCESS; 233 } 234 235 /* 236 * Open a session with EdgeLock Enclave. It returns a session handle. 237 * 238 * @session_handle EdgeLock Enclave session handle 239 */ 240 static TEE_Result __maybe_unused imx_ele_session_open(uint32_t *session_handle) 241 { 242 TEE_Result res = TEE_ERROR_GENERIC; 243 struct open_session_cmd { 244 uint8_t rsvd1; 245 uint8_t interrupt_num; 246 uint16_t rsvd2; 247 uint8_t priority; 248 uint8_t op_mode; 249 uint16_t rsvd3; 250 } __packed cmd = { 251 .rsvd1 = 0, 252 .interrupt_num = ELE_MU_IRQ, 253 .rsvd2 = 0, 254 .priority = 0, 255 .op_mode = 0, 256 .rsvd3 = 0, 257 }; 258 struct open_session_rsp { 259 uint32_t rsp_code; 260 uint32_t session_handle; 261 } rsp = { }; 262 struct imx_mu_msg msg = { 263 .header.version = ELE_VERSION_HSM, 264 .header.size = SIZE_MSG_32(cmd), 265 .header.tag = ELE_REQUEST_TAG, 266 .header.command = ELE_CMD_SESSION_OPEN, 267 }; 268 269 assert(session_handle); 270 271 memcpy(msg.data.u8, &cmd, sizeof(cmd)); 272 273 res = imx_ele_call(&msg); 274 if (res) 275 return res; 276 277 memcpy(&rsp, msg.data.u8, sizeof(rsp)); 278 279 *session_handle = rsp.session_handle; 280 281 return TEE_SUCCESS; 282 } 283 284 /* 285 * Close a session with EdgeLock Enclave. 286 * 287 * @session_handle EdgeLock Enclave session handle 288 */ 289 static TEE_Result __maybe_unused imx_ele_session_close(uint32_t session_handle) 290 { 291 struct close_session_cmd { 292 uint32_t session_handle; 293 } cmd = { 294 .session_handle = session_handle, 295 }; 296 struct imx_mu_msg msg = { 297 .header.version = ELE_VERSION_HSM, 298 .header.size = SIZE_MSG_32(cmd), 299 .header.tag = ELE_REQUEST_TAG, 300 .header.command = ELE_CMD_SESSION_CLOSE, 301 }; 302 303 memcpy(msg.data.u8, &cmd, sizeof(cmd)); 304 305 return imx_ele_call(&msg); 306 } 307 308 static TEE_Result imx_ele_get_device_info(struct get_info_rsp *rsp) 309 { 310 TEE_Result res = TEE_ERROR_GENERIC; 311 struct imx_ele_buf output = { }; 312 struct { 313 uint32_t addr_msb; 314 uint32_t addr_lsb; 315 uint16_t size; 316 } __packed cmd = { }; 317 struct imx_mu_msg msg = { 318 .header.version = ELE_VERSION_BASELINE, 319 .header.size = SIZE_MSG_32(cmd), 320 .header.tag = ELE_REQUEST_TAG, 321 .header.command = ELE_CMD_GET_INFO, 322 }; 323 324 if (!rsp) 325 return TEE_ERROR_BAD_PARAMETERS; 326 327 res = imx_ele_buf_alloc(&output, NULL, sizeof(*rsp)); 328 if (res) 329 goto out; 330 331 cmd.addr_msb = output.paddr_msb; 332 cmd.addr_lsb = output.paddr_lsb; 333 cmd.size = sizeof(*rsp); 334 335 memcpy(msg.data.u8, &cmd, sizeof(cmd)); 336 337 res = imx_ele_call(&msg); 338 if (res) 339 goto out; 340 341 res = imx_ele_buf_copy(&output, (uint8_t *)rsp, sizeof(*rsp)); 342 out: 343 imx_ele_buf_free(&output); 344 345 return res; 346 } 347 348 int tee_otp_get_die_id(uint8_t *buffer, size_t len) 349 { 350 static uint32_t uid[4]; 351 static bool is_fetched; 352 struct get_info_rsp rsp = { }; 353 354 assert(buffer && len); 355 356 if (!is_fetched) { 357 if (imx_ele_get_device_info(&rsp)) 358 panic("Fail to get the device UID"); 359 360 memcpy(uid, rsp.uid, MIN(sizeof(rsp.uid), len)); 361 is_fetched = true; 362 } 363 364 memcpy(buffer, uid, MIN(sizeof(uid), len)); 365 366 return 0; 367 } 368 369 /* 370 * Initialize EdgeLock Enclave services 371 */ 372 static TEE_Result imx_ele_sab_init(void) 373 { 374 struct imx_mu_msg msg = { 375 .header.version = ELE_VERSION_HSM, 376 .header.size = 1, 377 .header.tag = ELE_REQUEST_TAG, 378 .header.command = ELE_CMD_SAB_INIT, 379 }; 380 381 return imx_ele_call(&msg); 382 } 383 384 driver_init(imx_ele_sab_init); 385 386 #if defined(CFG_MX93) || defined(CFG_MX91) 387 static TEE_Result imx_ele_derive_key(const uint8_t *ctx, size_t ctx_size, 388 uint8_t *key, size_t key_size) 389 { 390 TEE_Result res = TEE_ERROR_GENERIC; 391 struct key_derive_cmd { 392 uint32_t key_addr_msb; 393 uint32_t key_addr_lsb; 394 uint32_t ctx_addr_msb; 395 uint32_t ctx_addr_lsb; 396 uint16_t key_size; 397 uint16_t ctx_size; 398 uint32_t crc; 399 } __packed cmd = { }; 400 struct imx_mu_msg msg = { 401 .header.version = ELE_VERSION_BASELINE, 402 .header.size = SIZE_MSG_32(cmd), 403 .header.tag = ELE_REQUEST_TAG, 404 .header.command = ELE_CMD_DERIVE_KEY, 405 }; 406 struct imx_ele_buf ele_ctx = { }; 407 struct imx_ele_buf ele_key = { }; 408 409 assert(ctx && key); 410 411 if (key_size != 16 && key_size != 32) 412 return TEE_ERROR_BAD_PARAMETERS; 413 414 res = imx_ele_buf_alloc(&ele_ctx, ctx, ctx_size); 415 if (res) 416 goto out; 417 418 res = imx_ele_buf_alloc(&ele_key, key, key_size); 419 if (res) 420 goto out; 421 422 cmd.key_addr_lsb = ele_key.paddr_lsb; 423 cmd.key_addr_msb = ele_key.paddr_msb; 424 cmd.key_size = key_size; 425 426 cmd.ctx_addr_lsb = ele_ctx.paddr_lsb; 427 cmd.ctx_addr_msb = ele_ctx.paddr_msb; 428 cmd.ctx_size = ctx_size; 429 430 memcpy(msg.data.u8, &cmd, sizeof(cmd)); 431 update_crc(&msg); 432 433 res = imx_ele_call(&msg); 434 if (res) 435 goto out; 436 437 res = imx_ele_buf_copy(&ele_key, key, key_size); 438 out: 439 imx_ele_buf_free(&ele_key); 440 imx_ele_buf_free(&ele_ctx); 441 442 return res; 443 } 444 445 TEE_Result tee_otp_get_hw_unique_key(struct tee_hw_unique_key *hwkey) 446 { 447 static const char pattern[] = "TEE_for_HUK_ELE"; 448 static uint8_t key[HW_UNIQUE_KEY_LENGTH]; 449 static bool is_fetched; 450 451 if (is_fetched) 452 goto out; 453 454 if (imx_ele_derive_key((const uint8_t *)pattern, sizeof(pattern), key, 455 sizeof(key))) 456 panic("Fail to get HUK from ELE"); 457 458 is_fetched = true; 459 out: 460 memcpy(hwkey->data, key, 461 MIN(sizeof(key), (size_t)HW_UNIQUE_KEY_LENGTH)); 462 463 return TEE_SUCCESS; 464 } 465 466 /* 467 * Get the current state of the ELE TRNG 468 */ 469 static TEE_Result imx_ele_rng_get_trng_state(void) 470 { 471 TEE_Result res = TEE_ERROR_GENERIC; 472 struct rng_get_trng_state_msg_rsp { 473 uint32_t rsp_code; 474 uint8_t trng_state; 475 uint8_t csal_state; 476 } __packed rsp = { }; 477 struct imx_mu_msg msg = { 478 .header.version = ELE_VERSION_BASELINE, 479 .header.size = 1, 480 .header.tag = ELE_REQUEST_TAG, 481 .header.command = ELE_CMD_TRNG_STATE, 482 }; 483 484 res = imx_ele_call(&msg); 485 if (res) 486 return res; 487 488 memcpy(&rsp, msg.data.u8, sizeof(rsp)); 489 490 if (rsp.trng_state != IMX_ELE_TRNG_STATUS_READY) 491 return TEE_ERROR_BUSY; 492 else 493 return TEE_SUCCESS; 494 } 495 496 /* 497 * Get random data from the EdgeLock Enclave. 498 * 499 * This function can be called when the MMU is off or on. 500 * virtual/physical address translation and cache maintenance 501 * is performed if needed. 502 * 503 * @buffer: data output 504 * @size: RNG data size 505 */ 506 static TEE_Result imx_ele_rng_get_random(uint8_t *buffer, size_t size) 507 { 508 TEE_Result res = TEE_ERROR_GENERIC; 509 struct imx_ele_buf rng = { }; 510 struct rng_get_random_cmd { 511 uint32_t addr_msb; 512 uint32_t addr_lsb; 513 uint32_t size; 514 } cmd = { }; 515 struct imx_mu_msg msg = { 516 .header.version = ELE_VERSION_HSM, 517 .header.size = SIZE_MSG_32(cmd), 518 .header.tag = ELE_REQUEST_TAG, 519 .header.command = ELE_CMD_RNG_GET, 520 }; 521 522 if (!buffer || !size) 523 return TEE_ERROR_BAD_PARAMETERS; 524 525 if (cpu_mmu_enabled()) { 526 res = imx_ele_buf_alloc(&rng, NULL, size); 527 if (res != TEE_SUCCESS) 528 return res; 529 530 cmd.addr_msb = rng.paddr_msb; 531 cmd.addr_lsb = rng.paddr_lsb; 532 } else { 533 paddr_t pa = (paddr_t)buffer; 534 535 if (!IS_ALIGNED_WITH_TYPE(pa, uint32_t)) 536 return TEE_ERROR_BAD_PARAMETERS; 537 538 reg_pair_from_64((uint64_t)pa, &cmd.addr_msb, &cmd.addr_lsb); 539 } 540 541 cmd.size = (uint32_t)size; 542 543 memcpy(msg.data.u8, &cmd, sizeof(cmd)); 544 545 res = imx_ele_call(&msg); 546 if (res) 547 goto out; 548 549 if (cpu_mmu_enabled()) 550 res = imx_ele_buf_copy(&rng, buffer, size); 551 out: 552 imx_ele_buf_free(&rng); 553 554 return res; 555 } 556 557 unsigned long plat_get_aslr_seed(void) 558 { 559 uint64_t timeout = timeout_init_us(10 * 1000); 560 unsigned long __aligned(CACHELINE_SIZE) aslr = 0; 561 562 /* 563 * Check the current TRNG state of the ELE. The TRNG must be 564 * started with a command earlier in the boot to allow the TRNG 565 * to generate enough entropy. 566 */ 567 while (imx_ele_rng_get_trng_state() == TEE_ERROR_BUSY) 568 if (timeout_elapsed(timeout)) 569 panic("ELE RNG is busy"); 570 571 if (imx_ele_rng_get_random((uint8_t *)&aslr, sizeof(aslr))) 572 panic("Cannot retrieve random data from ELE"); 573 574 return aslr; 575 } 576 577 #ifndef CFG_WITH_SOFTWARE_PRNG 578 TEE_Result hw_get_random_bytes(void *buf, size_t len) 579 { 580 return imx_ele_rng_get_random((uint8_t *)buf, len); 581 } 582 #endif /* CFG_WITH_SOFTWARE_PRNG */ 583 #endif /* CFG_MX93 || CFG_MX91 */ 584