xref: /optee_os/core/drivers/crypto/caam/caam_rng.c (revision 4576dbb38a6f39534ba4a385eb647b61209f440c)
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