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