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