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