1 // SPDX-License-Identifier: BSD-2-Clause 2 /** 3 * Copyright 2017-2019 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 default: 241 /* Wait until one of the data buffer completes */ 242 do { 243 wait_jobs = 0; 244 for (idx = 0; idx < RNG_DATABUF_NB; idx++) { 245 rng = &rng_privdata->databuf[idx]; 246 wait_jobs |= rng->job_id; 247 248 if (atomic_load_u32(&rng->status) == DATA_OK) { 249 RNG_TRACE("RNG Data buffer #%" PRIu32 250 " ready", 251 idx); 252 rng_privdata->dataidx = idx; 253 return CAAM_NO_ERROR; 254 } 255 } 256 257 if (!wait_jobs) { 258 RNG_TRACE("There are no Data Buffers ongoing"); 259 return CAAM_FAILURE; 260 } 261 262 /* Need to wait until one of the jobs completes */ 263 (void)caam_jr_dequeue(wait_jobs, 100); 264 } while (loop--); 265 266 break; 267 } 268 269 return CAAM_FAILURE; 270 } 271 272 /* 273 * Return the requested random data 274 * 275 * @buf [out] data buffer 276 * @len number of bytes to returns 277 */ 278 static TEE_Result do_rng_read(uint8_t *buf, size_t len) 279 { 280 struct rngdata *rng = NULL; 281 size_t remlen = len; 282 uint8_t *rngbuf = buf; 283 284 if (!rng_privdata) { 285 RNG_TRACE("RNG Driver not initialized"); 286 return TEE_ERROR_BAD_STATE; 287 } 288 289 if (!rng_privdata->instantiated) { 290 RNG_TRACE("RNG Driver not initialized"); 291 return TEE_ERROR_BAD_STATE; 292 } 293 294 do { 295 if (do_check_data() != CAAM_NO_ERROR) { 296 RNG_TRACE("No Data available or Error"); 297 return TEE_ERROR_BAD_STATE; 298 } 299 300 rng = &rng_privdata->databuf[rng_privdata->dataidx]; 301 RNG_TRACE("Context #%" PRIu8 302 " contains %zu data asked %zu (%zu)", 303 rng_privdata->dataidx, rng->size - rng->rdindex, 304 remlen, len); 305 306 /* Check that current context data are available */ 307 if ((rng->size - rng->rdindex) <= remlen) { 308 /* 309 * There is no or just enough data available, 310 * copy all data 311 */ 312 RNG_TRACE("Copy all available data"); 313 memcpy(rngbuf, &rng->data[rng->rdindex], 314 rng->size - rng->rdindex); 315 316 remlen -= rng->size - rng->rdindex; 317 rngbuf += rng->size - rng->rdindex; 318 /* Set the RNG data status as empty */ 319 atomic_store_u32(&rng->status, DATA_EMPTY); 320 } else { 321 /* There is enough data in the current context */ 322 RNG_TRACE("Copy %zu data", remlen); 323 memcpy(rngbuf, &rng->data[rng->rdindex], remlen); 324 rng->rdindex += remlen; 325 remlen = 0; 326 } 327 } while (remlen); 328 329 return TEE_SUCCESS; 330 } 331 332 /* Initialize the RNG module to generate data */ 333 static enum caam_status caam_rng_init_data(void) 334 { 335 enum caam_status retstatus = CAAM_FAILURE; 336 struct rngdata *rng = NULL; 337 unsigned int idx = 0; 338 339 for (idx = 0; idx < RNG_DATABUF_NB; idx++) { 340 rng = &rng_privdata->databuf[idx]; 341 retstatus = prepare_gen_desc(rng); 342 343 if (retstatus != CAAM_NO_ERROR) 344 break; 345 } 346 347 return retstatus; 348 } 349 #endif /* CFG_NXP_CAAM_RNG_DRV */ 350 351 /* 352 * Prepares the instantiation descriptor 353 * 354 * @nb_sh Number of the State Handle 355 * @sh_status State Handles status 356 * @desc Reference to the descriptor 357 * @desc [out] Descriptor filled 358 */ 359 static void prepare_inst_desc(uint32_t nb_sh, uint32_t sh_status, 360 uint32_t *desc) 361 { 362 bool key_loaded = false; 363 unsigned int sh_idx = 0; 364 unsigned int nb_max_sh = nb_sh; 365 366 /* Read the SH and secure key status */ 367 key_loaded = caam_hal_rng_key_loaded(rng_privdata->baseaddr); 368 RNG_TRACE("RNG SH Status 0x%08" PRIx32 " - Key Status %" PRId8, 369 sh_status, key_loaded); 370 371 while (sh_status & BIT(sh_idx)) 372 sh_idx++; 373 374 RNG_TRACE("Instantiation start at SH%" PRIu32 " (%" PRIu32 ")", sh_idx, 375 nb_max_sh); 376 377 /* Don't set the descriptor header now */ 378 caam_desc_init(desc); 379 caam_desc_add_word(desc, DESC_HEADER(0)); 380 /* First State Handle to instantiate */ 381 caam_desc_add_word(desc, RNG_SH_INST(sh_idx)); 382 383 /* Next State Handles */ 384 for (sh_idx++; sh_idx < nb_max_sh; sh_idx++) { 385 if (!(sh_status & BIT(sh_idx))) { 386 /* 387 * If there is more SH to instantiate, add a wait loop 388 * followed by a reset of the done status to execute 389 * next command 390 */ 391 caam_desc_add_word(desc, 392 JUMP_C1_LOCAL(ALL_COND_TRUE, 393 JMP_COND(NONE), 1)); 394 caam_desc_add_word(desc, 395 LD_NOCLASS_IMM(REG_CLEAR_WRITTEN, 396 sizeof(uint32_t))); 397 caam_desc_add_word(desc, 0x1); 398 caam_desc_add_word(desc, RNG_SH_INST(sh_idx)); 399 } 400 } 401 402 /* Load the Key if needed */ 403 if (!key_loaded) { 404 /* 405 * Add a wait loop while previous operation not completed, 406 * followed by a register clear before executing next command 407 */ 408 caam_desc_add_word(desc, JUMP_C1_LOCAL(ALL_COND_TRUE, 409 JMP_COND(NONE), 1)); 410 caam_desc_add_word(desc, LD_NOCLASS_IMM(REG_CLEAR_WRITTEN, 411 sizeof(uint32_t))); 412 caam_desc_add_word(desc, 0x1); 413 caam_desc_add_word(desc, RNG_GEN_SECKEYS); 414 } 415 416 RNG_DUMPDESC(desc); 417 } 418 419 enum caam_status caam_rng_instantiation(void) 420 { 421 enum caam_status retstatus = CAAM_FAILURE; 422 struct caam_jobctx jobctx = {}; 423 uint32_t *desc = NULL; 424 uint32_t sh_status = 0; 425 uint32_t nb_sh = 0; 426 uint32_t sh_mask = 0; 427 uint32_t inc_delay = 0; 428 429 RNG_TRACE("RNG Instantation"); 430 431 /* Check if RNG is already instantiated */ 432 if (caam_hal_rng_instantiated(rng_privdata->baseaddr)) { 433 RNG_TRACE("RNG already instantiated"); 434 retstatus = CAAM_NO_ERROR; 435 goto end_inst; 436 } 437 438 /* 439 * RNG needs to be instantiated. Allocate and prepare the 440 * Job Descriptor 441 */ 442 443 /* Calculate the State Handles bit mask */ 444 nb_sh = caam_hal_rng_get_nb_sh(rng_privdata->baseaddr); 445 sh_mask = GENMASK_32(nb_sh - 1, 0); 446 447 /* 448 * The maximum size of the descriptor is: 449 * |----------------------| 450 * | Header | = 1 451 * |----------------------| 452 * | First instantation | = 1 453 * |----------------------|------------------------- 454 * | wait complete | = 1 455 * |----------------------| 456 * | Clear done status | Repeat (nb_sh - 1) 457 * | | = 2 458 * |----------------------| 459 * | next SH instantation | = 1 460 * |----------------------|------------------------- 461 * | wait complete | = 1 462 * |----------------------| 463 * | Clear done status | = 2 464 * | | 465 * |----------------------| 466 * | Generate Secure Keys | = 1 467 * |----------------------| 468 * | Pad with a 0 | = 1 469 */ 470 desc = caam_calloc_desc(2 + (nb_sh - 1) * 4 + 4 + 1); 471 if (!desc) { 472 RNG_TRACE("Descriptor Allocation error"); 473 retstatus = CAAM_OUT_MEMORY; 474 goto end_inst; 475 } 476 477 jobctx.desc = desc; 478 479 do { 480 /* Check if all State Handles are instantiated */ 481 sh_status = caam_hal_rng_get_sh_status(rng_privdata->baseaddr); 482 if ((sh_status & sh_mask) == sh_mask) { 483 RNG_TRACE("RNG All SH are instantiated (0x%08" PRIx32 484 ")", 485 sh_status); 486 retstatus = CAAM_NO_ERROR; 487 goto end_inst; 488 } 489 490 if (sh_status == 0) { 491 retstatus = caam_hal_rng_kick(rng_privdata->baseaddr, 492 inc_delay); 493 RNG_TRACE("RNG Kick (inc=%" PRIu32 ") ret 0x%08x", 494 inc_delay, retstatus); 495 if (retstatus != CAAM_NO_ERROR) { 496 retstatus = CAAM_FAILURE; 497 goto end_inst; 498 } 499 inc_delay += 200; 500 } 501 502 prepare_inst_desc(nb_sh, sh_status, desc); 503 504 retstatus = caam_jr_enqueue(&jobctx, NULL); 505 RNG_TRACE("RNG Job returned 0x%08x", retstatus); 506 507 if (retstatus != CAAM_NO_ERROR && 508 retstatus != CAAM_JOB_STATUS) 509 goto end_inst; 510 511 if (retstatus == CAAM_JOB_STATUS) { 512 RNG_TRACE("RNG Job status 0x%08" PRIx32, jobctx.status); 513 if ((JRSTA_SRC_GET(jobctx.status) != JRSTA_SRC(CCB)) || 514 (JRSTA_CCB_GET_ERR(jobctx.status) != 515 (JRSTA_CCB_CHAID_RNG | JRSTA_CCB_ERRID_HW))) 516 retstatus = CAAM_FAILURE; 517 else 518 retstatus = CAAM_NO_ERROR; 519 } 520 } while (retstatus == CAAM_NO_ERROR); 521 522 end_inst: 523 if (retstatus == CAAM_NO_ERROR) 524 rng_privdata->instantiated = true; 525 526 caam_free_desc(&desc); 527 528 RNG_TRACE("RNG Instantiation return 0x%08x", retstatus); 529 530 return retstatus; 531 } 532 533 enum caam_status caam_rng_init(vaddr_t ctrl_addr) 534 { 535 enum caam_status retstatus = CAAM_FAILURE; 536 537 RNG_TRACE("Initialization"); 538 retstatus = do_allocate(); 539 if (retstatus == CAAM_NO_ERROR) { 540 rng_privdata->baseaddr = ctrl_addr; 541 retstatus = caam_rng_instantiation(); 542 } 543 544 #ifdef CFG_NXP_CAAM_RNG_DRV 545 if (retstatus == CAAM_NO_ERROR) 546 retstatus = caam_rng_init_data(); 547 #endif 548 549 if (retstatus != CAAM_NO_ERROR) 550 do_free(); 551 552 return retstatus; 553 } 554 555 #ifdef CFG_NXP_CAAM_RNG_DRV 556 TEE_Result crypto_rng_read(void *buf, size_t blen) 557 { 558 if (!buf) 559 return TEE_ERROR_BAD_PARAMETERS; 560 561 return do_rng_read(buf, blen); 562 } 563 564 uint8_t hw_get_random_byte(void) 565 { 566 uint8_t data = 0; 567 568 if (do_rng_read(&data, 1) != TEE_SUCCESS) 569 panic(); 570 571 return data; 572 } 573 574 void plat_rng_init(void) 575 { 576 } 577 #endif 578