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