1 /*
2  * Copyright (c) 2017 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/sys/atomic.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/drivers/entropy.h>
10 #include <string.h>
11 
12 static const struct device *const entropy_dev =
13 	DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy));
14 
rand_get(uint8_t * dst,size_t outlen,bool csrand)15 static int rand_get(uint8_t *dst, size_t outlen, bool csrand)
16 {
17 	uint32_t random_num;
18 	int ret;
19 
20 	__ASSERT(device_is_ready(entropy_dev), "Entropy device %s not ready",
21 		 entropy_dev->name);
22 
23 	ret = entropy_get_entropy(entropy_dev, dst, outlen);
24 
25 	if (unlikely(ret < 0)) {
26 		/* Don't try to fill the buffer in case of
27 		 * cryptographically secure random numbers, just
28 		 * propagate the driver error.
29 		 */
30 		if (csrand) {
31 			return ret;
32 		}
33 
34 		/* Use system timer in case the entropy device couldn't deliver
35 		 * 32-bit of data.  There's not much that can be done in this
36 		 * situation.  An __ASSERT() isn't used here as the HWRNG might
37 		 * still be gathering entropy during early boot situations.
38 		 */
39 
40 		uint32_t len = 0;
41 		uint32_t blocksize = 4;
42 
43 		while (len < outlen) {
44 			size_t copylen = outlen - len;
45 
46 			if (copylen > blocksize) {
47 				copylen = blocksize;
48 			}
49 
50 			random_num = k_cycle_get_32();
51 			(void)memcpy(&(dst[len]), &random_num, copylen);
52 			len += copylen;
53 		}
54 	}
55 
56 	return 0;
57 }
58 
59 #if defined(CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR)
z_impl_sys_rand_get(void * dst,size_t outlen)60 void z_impl_sys_rand_get(void *dst, size_t outlen)
61 {
62 	rand_get(dst, outlen, false);
63 }
64 #endif /* CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR */
65 
66 #if defined(CONFIG_HARDWARE_DEVICE_CS_GENERATOR)
67 
z_impl_sys_csrand_get(void * dst,size_t outlen)68 int z_impl_sys_csrand_get(void *dst, size_t outlen)
69 {
70 	if (rand_get(dst, outlen, true) != 0) {
71 		/* Is it the only error it should return ? entropy_sam
72 		 * can return -ETIMEDOUT for example
73 		 */
74 		return -EIO;
75 	}
76 
77 	return 0;
78 }
79 
80 #endif /* CONFIG_HARDWARE_DEVICE_CS_GENERATOR */
81