1 // SPDX-License-Identifier: BSD-2-Clause 2 /** 3 * Copyright 2017-2021 NXP 4 * 5 * Brief CAAM Random Number Generator manager. 6 * Implementation of RNG functions. 7 */ 8 #include <atomic.h> 9 #include <caam_common.h> 10 #include <caam_hal_rng.h> 11 #include <caam_jr.h> 12 #include <caam_rng.h> 13 #include <caam_utils_mem.h> 14 #include <crypto/crypto.h> 15 #include <kernel/panic.h> 16 #include <mm/core_memprot.h> 17 #include <rng_support.h> 18 #include <tee/cache.h> 19 #include <tee/tee_cryp_utl.h> 20 #include <string.h> 21 22 /* 23 * Define the RNG Data buffer size and number 24 */ 25 #define RNG_DATABUF_SIZE 1024 26 #define RNG_DATABUF_NB 2 27 28 /* 29 * Define the number of descriptor entry to generate random data 30 */ 31 #define RNG_GEN_DESC_ENTRIES 5 32 33 /* 34 * Status of the data generation 35 */ 36 enum rngsta { 37 DATA_EMPTY = 0, /* Data bufer empty */ 38 DATA_ONGOING, /* Data generation on going */ 39 DATA_FAILURE, /* Error during data generation */ 40 DATA_OK, /* Data generation complete with success */ 41 }; 42 43 /* 44 * RNG Data generation 45 */ 46 struct rngdata { 47 struct caam_jobctx jobctx; /* Job Ring Context */ 48 uint32_t job_id; /* Job Id enqueued */ 49 50 uint8_t *data; /* Random Data buffer */ 51 size_t size; /* Size in bytes of the Random data buffer */ 52 size_t rdindex; /* Current data index in the buffer */ 53 54 enum rngsta status; /* Status of the data generation */ 55 }; 56 57 /* 58 * RNG module private data 59 */ 60 struct rng_privdata { 61 vaddr_t baseaddr; /* RNG base address */ 62 bool instantiated; /* RNG instantiated */ 63 bool pr_enabled; /* RNG prediction resistance */ 64 struct rngdata databuf[RNG_DATABUF_NB]; /* RNG Data generation */ 65 uint8_t dataidx; /* Current RNG Data buffer */ 66 }; 67 68 static struct rng_privdata *rng_privdata; 69 70 /* Allocate and initialize module private data */ 71 static enum caam_status do_allocate(void) 72 { 73 struct rngdata *rngdata = NULL; 74 unsigned int idx = 0; 75 76 /* Allocate the Module resources */ 77 rng_privdata = caam_calloc(sizeof(*rng_privdata)); 78 if (!rng_privdata) { 79 RNG_TRACE("Private Data allocation error"); 80 return CAAM_OUT_MEMORY; 81 } 82 83 rng_privdata->instantiated = false; 84 85 /* Allocates the RNG Data Buffers */ 86 for (idx = 0; idx < RNG_DATABUF_NB; idx++) { 87 rngdata = &rng_privdata->databuf[idx]; 88 rngdata->data = caam_calloc_align(RNG_DATABUF_SIZE); 89 if (!rngdata->data) 90 return CAAM_OUT_MEMORY; 91 92 rngdata->size = RNG_DATABUF_SIZE; 93 rngdata->jobctx.desc = caam_calloc_desc(RNG_GEN_DESC_ENTRIES); 94 if (!rngdata->jobctx.desc) 95 return CAAM_OUT_MEMORY; 96 } 97 98 return CAAM_NO_ERROR; 99 } 100 101 /* Free module private data */ 102 static void do_free(void) 103 { 104 struct rngdata *rng = NULL; 105 unsigned int idx = 0; 106 107 if (rng_privdata) { 108 for (idx = 0; idx < RNG_DATABUF_NB; idx++) { 109 rng = &rng_privdata->databuf[idx]; 110 111 /* Check if there is a Job ongoing to cancel it */ 112 if (atomic_load_u32(&rng->status) == DATA_ONGOING) 113 caam_jr_cancel(rng->job_id); 114 115 caam_free_desc(&rng->jobctx.desc); 116 caam_free(rng->data); 117 rng->data = NULL; 118 } 119 120 caam_free(rng_privdata); 121 rng_privdata = NULL; 122 } 123 } 124 125 #ifdef CFG_NXP_CAAM_RNG_DRV 126 /* 127 * RNG data generation job ring callback completion 128 * 129 * @jobctx RNG data JR Job Context 130 */ 131 static void rng_data_done(struct caam_jobctx *jobctx) 132 { 133 struct rngdata *rng = jobctx->context; 134 135 RNG_TRACE("RNG Data id 0x%08" PRIx32 " done with status 0x%" PRIx32, 136 rng->job_id, jobctx->status); 137 138 if (JRSTA_SRC_GET(jobctx->status) == JRSTA_SRC(NONE)) { 139 atomic_store_u32(&rng->status, DATA_OK); 140 141 /* Invalidate the data buffer to ensure software gets it */ 142 cache_operation(TEE_CACHEINVALIDATE, rng->data, rng->size); 143 } else { 144 RNG_TRACE("RNG Data completion in error 0x%" PRIx32, 145 jobctx->status); 146 atomic_store_u32(&rng->status, DATA_FAILURE); 147 } 148 149 rng->job_id = 0; 150 rng->rdindex = 0; 151 } 152 153 /* 154 * Prepares the data generation descriptors 155 * 156 * @rng Reference to the RNG Data object 157 */ 158 static enum caam_status prepare_gen_desc(struct rngdata *rng) 159 { 160 paddr_t paddr = 0; 161 uint32_t *desc = NULL; 162 uint32_t op = RNG_GEN_DATA; 163 164 if (rng_privdata->pr_enabled) 165 op |= ALGO_RNG_PR; 166 167 /* Convert the buffer virtual address to physical address */ 168 paddr = virt_to_phys(rng->data); 169 if (!paddr) 170 return CAAM_FAILURE; 171 172 desc = rng->jobctx.desc; 173 174 caam_desc_init(desc); 175 caam_desc_add_word(desc, DESC_HEADER(0)); 176 caam_desc_add_word(desc, op); 177 caam_desc_add_word(desc, FIFO_ST(CLASS_NO, RNG_TO_MEM, rng->size)); 178 caam_desc_add_ptr(desc, paddr); 179 180 RNG_DUMPDESC(desc); 181 182 /* Prepare the job context */ 183 rng->jobctx.context = rng; 184 rng->jobctx.callback = rng_data_done; 185 return CAAM_NO_ERROR; 186 } 187 188 /* 189 * Launches a RNG Data generation 190 * 191 * @rng RNG Data context 192 */ 193 static enum caam_status do_rng_start(struct rngdata *rng) 194 { 195 enum caam_status ret = CAAM_FAILURE; 196 197 /* Ensure that data buffer is visible from the HW */ 198 cache_operation(TEE_CACHEFLUSH, rng->data, rng->size); 199 200 rng->job_id = 0; 201 atomic_store_u32(&rng->status, DATA_EMPTY); 202 203 ret = caam_jr_enqueue(&rng->jobctx, &rng->job_id); 204 205 if (ret == CAAM_PENDING) { 206 atomic_store_u32(&rng->status, DATA_ONGOING); 207 ret = CAAM_NO_ERROR; 208 } else { 209 RNG_TRACE("RNG Job Ring Error 0x%08x", ret); 210 atomic_store_u32(&rng->status, DATA_FAILURE); 211 ret = CAAM_FAILURE; 212 } 213 214 return ret; 215 } 216 217 /* Checks if there are random data available */ 218 static enum caam_status do_check_data(void) 219 { 220 enum caam_status ret = CAAM_FAILURE; 221 struct rngdata *rng = NULL; 222 uint32_t wait_jobs = 0; 223 unsigned int idx = 0; 224 unsigned int loop = 4; 225 226 /* Check if there is a RNG Job to be run */ 227 for (idx = 0; idx < RNG_DATABUF_NB; idx++) { 228 rng = &rng_privdata->databuf[idx]; 229 if (atomic_load_u32(&rng->status) == DATA_EMPTY) { 230 RNG_TRACE("Start RNG #%" PRIu32 " data generation", 231 idx); 232 ret = do_rng_start(rng); 233 if (ret != CAAM_NO_ERROR) 234 return CAAM_FAILURE; 235 } 236 } 237 238 /* Check if the current data buffer contains data */ 239 rng = &rng_privdata->databuf[rng_privdata->dataidx]; 240 241 switch (atomic_load_u32(&rng->status)) { 242 case DATA_OK: 243 return CAAM_NO_ERROR; 244 245 case DATA_FAILURE: 246 return CAAM_FAILURE; 247 248 default: 249 /* Wait until one of the data buffer completes */ 250 do { 251 wait_jobs = 0; 252 for (idx = 0; idx < RNG_DATABUF_NB; idx++) { 253 rng = &rng_privdata->databuf[idx]; 254 wait_jobs |= rng->job_id; 255 256 if (atomic_load_u32(&rng->status) == DATA_OK) { 257 RNG_TRACE("RNG Data buffer #%" PRIu32 258 " ready", 259 idx); 260 rng_privdata->dataidx = idx; 261 return CAAM_NO_ERROR; 262 } 263 } 264 265 if (!wait_jobs) { 266 RNG_TRACE("There are no Data Buffers ongoing"); 267 return CAAM_FAILURE; 268 } 269 270 /* Need to wait until one of the jobs completes */ 271 (void)caam_jr_dequeue(wait_jobs, 100); 272 } while (loop--); 273 274 break; 275 } 276 277 return CAAM_FAILURE; 278 } 279 280 /* 281 * Return the requested random data 282 * 283 * @buf [out] data buffer 284 * @len number of bytes to returns 285 */ 286 static TEE_Result do_rng_read(uint8_t *buf, size_t len) 287 { 288 struct rngdata *rng = NULL; 289 size_t remlen = len; 290 uint8_t *rngbuf = buf; 291 292 if (!rng_privdata) { 293 RNG_TRACE("RNG Driver not initialized"); 294 return TEE_ERROR_BAD_STATE; 295 } 296 297 if (!rng_privdata->instantiated) { 298 RNG_TRACE("RNG Driver not initialized"); 299 return TEE_ERROR_BAD_STATE; 300 } 301 302 do { 303 if (do_check_data() != CAAM_NO_ERROR) { 304 RNG_TRACE("No Data available or Error"); 305 return TEE_ERROR_BAD_STATE; 306 } 307 308 rng = &rng_privdata->databuf[rng_privdata->dataidx]; 309 RNG_TRACE("Context #%" PRIu8 310 " contains %zu data asked %zu (%zu)", 311 rng_privdata->dataidx, rng->size - rng->rdindex, 312 remlen, len); 313 314 /* Check that current context data are available */ 315 if ((rng->size - rng->rdindex) <= remlen) { 316 /* 317 * There is no or just enough data available, 318 * copy all data 319 */ 320 RNG_TRACE("Copy all available data"); 321 memcpy(rngbuf, &rng->data[rng->rdindex], 322 rng->size - rng->rdindex); 323 324 remlen -= rng->size - rng->rdindex; 325 rngbuf += rng->size - rng->rdindex; 326 /* Set the RNG data status as empty */ 327 atomic_store_u32(&rng->status, DATA_EMPTY); 328 } else { 329 /* There is enough data in the current context */ 330 RNG_TRACE("Copy %zu data", remlen); 331 memcpy(rngbuf, &rng->data[rng->rdindex], remlen); 332 rng->rdindex += remlen; 333 remlen = 0; 334 } 335 } while (remlen); 336 337 return TEE_SUCCESS; 338 } 339 340 /* Initialize the RNG module to generate data */ 341 static enum caam_status caam_rng_init_data(void) 342 { 343 enum caam_status retstatus = CAAM_FAILURE; 344 struct rngdata *rng = NULL; 345 unsigned int idx = 0; 346 347 for (idx = 0; idx < RNG_DATABUF_NB; idx++) { 348 rng = &rng_privdata->databuf[idx]; 349 retstatus = prepare_gen_desc(rng); 350 351 if (retstatus != CAAM_NO_ERROR) 352 break; 353 } 354 355 return retstatus; 356 } 357 #endif /* CFG_NXP_CAAM_RNG_DRV */ 358 359 /* 360 * Prepares the instantiation descriptor 361 * 362 * @nb_sh Number of the State Handle 363 * @sh_status State Handles status 364 * @desc Reference to the descriptor 365 * @desc [out] Descriptor filled 366 */ 367 static void prepare_inst_desc(uint32_t nb_sh, uint32_t sh_status, 368 uint32_t *desc) 369 { 370 bool key_loaded = false; 371 unsigned int sh_idx = 0; 372 unsigned int nb_max_sh = nb_sh; 373 374 /* Read the SH and secure key status */ 375 key_loaded = caam_hal_rng_key_loaded(rng_privdata->baseaddr); 376 RNG_TRACE("RNG SH Status 0x%08" PRIx32 " - Key Status %" PRId8, 377 sh_status, key_loaded); 378 379 while (sh_status & BIT(sh_idx)) 380 sh_idx++; 381 382 RNG_TRACE("Instantiation start at SH%" PRIu32 " (%" PRIu32 ")", sh_idx, 383 nb_max_sh); 384 385 /* Don't set the descriptor header now */ 386 caam_desc_init(desc); 387 caam_desc_add_word(desc, DESC_HEADER(0)); 388 /* First State Handle to instantiate */ 389 caam_desc_add_word(desc, RNG_SH_INST(sh_idx)); 390 391 /* Next State Handles */ 392 for (sh_idx++; sh_idx < nb_max_sh; sh_idx++) { 393 if (!(sh_status & BIT(sh_idx))) { 394 /* 395 * If there is more SH to instantiate, add a wait loop 396 * followed by a reset of the done status to execute 397 * next command 398 */ 399 caam_desc_add_word(desc, 400 JUMP_C1_LOCAL(ALL_COND_TRUE, 401 JMP_COND(NONE), 1)); 402 caam_desc_add_word(desc, 403 LD_NOCLASS_IMM(REG_CLEAR_WRITTEN, 404 sizeof(uint32_t))); 405 caam_desc_add_word(desc, 0x1); 406 caam_desc_add_word(desc, RNG_SH_INST(sh_idx)); 407 } 408 } 409 410 /* Load the Key if needed */ 411 if (!key_loaded) { 412 /* 413 * Add a wait loop while previous operation not completed, 414 * followed by a register clear before executing next command 415 */ 416 caam_desc_add_word(desc, JUMP_C1_LOCAL(ALL_COND_TRUE, 417 JMP_COND(NONE), 1)); 418 caam_desc_add_word(desc, LD_NOCLASS_IMM(REG_CLEAR_WRITTEN, 419 sizeof(uint32_t))); 420 caam_desc_add_word(desc, 0x1); 421 caam_desc_add_word(desc, RNG_GEN_SECKEYS); 422 } 423 424 RNG_DUMPDESC(desc); 425 } 426 427 enum caam_status caam_rng_instantiation(void) 428 { 429 enum caam_status retstatus = CAAM_FAILURE; 430 struct caam_jobctx jobctx = {}; 431 uint32_t *desc = NULL; 432 uint32_t sh_status = 0; 433 uint32_t nb_sh = 0; 434 uint32_t sh_mask = 0; 435 uint32_t inc_delay = 0; 436 437 RNG_TRACE("RNG Instantation"); 438 439 /* Check if RNG is already instantiated */ 440 retstatus = caam_hal_rng_instantiated(rng_privdata->baseaddr); 441 442 /* RNG is already instantiated or an error occurred */ 443 if (retstatus != CAAM_NOT_INIT) 444 goto end_inst; 445 446 /* 447 * RNG needs to be instantiated. Allocate and prepare the 448 * Job Descriptor 449 */ 450 451 /* Calculate the State Handles bit mask */ 452 nb_sh = caam_hal_rng_get_nb_sh(rng_privdata->baseaddr); 453 sh_mask = GENMASK_32(nb_sh - 1, 0); 454 455 /* 456 * The maximum size of the descriptor is: 457 * |----------------------| 458 * | Header | = 1 459 * |----------------------| 460 * | First instantation | = 1 461 * |----------------------|------------------------- 462 * | wait complete | = 1 463 * |----------------------| 464 * | Clear done status | Repeat (nb_sh - 1) 465 * | | = 2 466 * |----------------------| 467 * | next SH instantation | = 1 468 * |----------------------|------------------------- 469 * | wait complete | = 1 470 * |----------------------| 471 * | Clear done status | = 2 472 * | | 473 * |----------------------| 474 * | Generate Secure Keys | = 1 475 * |----------------------| 476 * | Pad with a 0 | = 1 477 */ 478 desc = caam_calloc_desc(2 + (nb_sh - 1) * 4 + 4 + 1); 479 if (!desc) { 480 RNG_TRACE("Descriptor Allocation error"); 481 retstatus = CAAM_OUT_MEMORY; 482 goto end_inst; 483 } 484 485 jobctx.desc = desc; 486 487 do { 488 /* Check if all State Handles are instantiated */ 489 sh_status = caam_hal_rng_get_sh_status(rng_privdata->baseaddr); 490 if ((sh_status & sh_mask) == sh_mask) { 491 RNG_TRACE("RNG All SH are instantiated (0x%08" PRIx32 492 ")", 493 sh_status); 494 retstatus = CAAM_NO_ERROR; 495 goto end_inst; 496 } 497 498 if (sh_status == 0) { 499 retstatus = caam_hal_rng_kick(rng_privdata->baseaddr, 500 inc_delay); 501 RNG_TRACE("RNG Kick (inc=%" PRIu32 ") ret 0x%08x", 502 inc_delay, retstatus); 503 if (retstatus != CAAM_NO_ERROR) { 504 retstatus = CAAM_FAILURE; 505 goto end_inst; 506 } 507 inc_delay += 200; 508 } 509 510 prepare_inst_desc(nb_sh, sh_status, desc); 511 512 retstatus = caam_jr_enqueue(&jobctx, NULL); 513 RNG_TRACE("RNG Job returned 0x%08x", retstatus); 514 515 if (retstatus != CAAM_NO_ERROR && 516 retstatus != CAAM_JOB_STATUS) 517 goto end_inst; 518 519 if (retstatus == CAAM_JOB_STATUS) { 520 RNG_TRACE("RNG Job status 0x%08" PRIx32, jobctx.status); 521 if ((JRSTA_SRC_GET(jobctx.status) != JRSTA_SRC(CCB)) || 522 (JRSTA_CCB_GET_ERR(jobctx.status) != 523 (JRSTA_CCB_CHAID_RNG | JRSTA_CCB_ERRID_HW))) 524 retstatus = CAAM_FAILURE; 525 else 526 retstatus = CAAM_NO_ERROR; 527 } 528 } while (retstatus == CAAM_NO_ERROR); 529 530 end_inst: 531 if (retstatus == CAAM_NO_ERROR) { 532 rng_privdata->instantiated = true; 533 rng_privdata->pr_enabled = 534 caam_hal_rng_pr_enabled(rng_privdata->baseaddr); 535 536 RNG_TRACE("RNG prediction resistance is %sabled", 537 rng_privdata->pr_enabled ? "en" : "dis"); 538 } 539 540 caam_free_desc(&desc); 541 542 RNG_TRACE("RNG Instantiation return 0x%08x", retstatus); 543 544 return retstatus; 545 } 546 547 enum caam_status caam_rng_init(vaddr_t ctrl_addr) 548 { 549 enum caam_status retstatus = CAAM_FAILURE; 550 551 RNG_TRACE("Initialization"); 552 retstatus = do_allocate(); 553 if (retstatus == CAAM_NO_ERROR) { 554 rng_privdata->baseaddr = ctrl_addr; 555 retstatus = caam_rng_instantiation(); 556 } 557 558 #ifdef CFG_NXP_CAAM_RNG_DRV 559 if (retstatus == CAAM_NO_ERROR) 560 retstatus = caam_rng_init_data(); 561 #endif 562 563 if (retstatus != CAAM_NO_ERROR) 564 do_free(); 565 566 return retstatus; 567 } 568 569 #ifdef CFG_NXP_CAAM_RNG_DRV 570 #ifdef CFG_WITH_SOFTWARE_PRNG 571 void plat_rng_init(void) 572 { 573 TEE_Result res = TEE_SUCCESS; 574 uint8_t buf[64] = { }; 575 576 res = do_rng_read(buf, sizeof(buf)); 577 if (res) { 578 EMSG("Failed to read RNG: %#" PRIx32, res); 579 panic(); 580 } 581 582 res = crypto_rng_init(buf, sizeof(buf)); 583 if (res) { 584 EMSG("Failed to initialize RNG: %#" PRIx32, res); 585 panic(); 586 } 587 588 RNG_TRACE("PRNG seeded from CAAM"); 589 } 590 #else /* !CFG_WITH_SOFTWARE_PRNG */ 591 TEE_Result hw_get_random_bytes(void *buf, size_t blen) 592 { 593 if (!buf) 594 return TEE_ERROR_BAD_PARAMETERS; 595 596 return do_rng_read(buf, blen); 597 } 598 599 void plat_rng_init(void) 600 { 601 } 602 #endif /* CFG_WITH_SOFTWARE_PRNG */ 603 #endif /* CFG_NXP_CAAM_RNG_DRV */ 604