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