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 */
do_allocate(void)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 */
do_free(void)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 */
rng_data_done(struct caam_jobctx * jobctx)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 */
prepare_gen_desc(struct rngdata * rng)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 */
do_rng_start(struct rngdata * rng)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 */
do_check_data(void)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 */
do_rng_read(uint8_t * buf,size_t len)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 */
caam_rng_init_data(void)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 */
prepare_inst_desc(uint32_t nb_sh,uint32_t sh_status,uint32_t * desc)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
caam_rng_instantiation(void)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
caam_rng_init(vaddr_t ctrl_addr)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
hw_get_random_bytes(void * buf,size_t blen)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
plat_rng_init(void)567 void plat_rng_init(void)
568 {
569 }
570 #endif
571