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 
15 #if defined(CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR)
z_impl_sys_rand32_get(void)16 uint32_t z_impl_sys_rand32_get(void)
17 {
18 	uint32_t random_num;
19 	int ret;
20 
21 	__ASSERT(device_is_ready(entropy_dev), "Entropy device %s not ready",
22 		 entropy_dev->name);
23 
24 	ret = entropy_get_entropy(entropy_dev, (uint8_t *)&random_num,
25 				  sizeof(random_num));
26 	if (unlikely(ret < 0)) {
27 		/* Use system timer in case the entropy device couldn't deliver
28 		 * 32-bit of data.  There's not much that can be done in this
29 		 * situation.  An __ASSERT() isn't used here as the HWRNG might
30 		 * still be gathering entropy during early boot situations.
31 		 */
32 
33 		random_num = k_cycle_get_32();
34 	}
35 
36 	return random_num;
37 }
38 #endif /* CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR */
39 
rand_get(uint8_t * dst,size_t outlen,bool csrand)40 static int rand_get(uint8_t *dst, size_t outlen, bool csrand)
41 {
42 	uint32_t random_num;
43 	int ret;
44 
45 	__ASSERT(device_is_ready(entropy_dev), "Entropy device %s not ready",
46 		 entropy_dev->name);
47 
48 	ret = entropy_get_entropy(entropy_dev, dst, outlen);
49 
50 	if (unlikely(ret < 0)) {
51 		/* Don't try to fill the buffer in case of
52 		 * cryptographically secure random numbers, just
53 		 * propagate the driver error.
54 		 */
55 		if (csrand) {
56 			return ret;
57 		}
58 
59 		/* Use system timer in case the entropy device couldn't deliver
60 		 * 32-bit of data.  There's not much that can be done in this
61 		 * situation.  An __ASSERT() isn't used here as the HWRNG might
62 		 * still be gathering entropy during early boot situations.
63 		 */
64 
65 		uint32_t len = 0;
66 		uint32_t blocksize = 4;
67 
68 		while (len < outlen) {
69 			size_t copylen = outlen - len;
70 
71 			if (copylen > blocksize) {
72 				copylen = blocksize;
73 			}
74 
75 			random_num = k_cycle_get_32();
76 			(void)memcpy(&(dst[len]), &random_num, copylen);
77 			len += copylen;
78 		}
79 	}
80 
81 	return 0;
82 }
83 
84 #if defined(CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR)
z_impl_sys_rand_get(void * dst,size_t outlen)85 void z_impl_sys_rand_get(void *dst, size_t outlen)
86 {
87 	rand_get(dst, outlen, false);
88 }
89 #endif /* CONFIG_ENTROPY_DEVICE_RANDOM_GENERATOR */
90 
91 #if defined(CONFIG_HARDWARE_DEVICE_CS_GENERATOR)
92 
z_impl_sys_csrand_get(void * dst,size_t outlen)93 int z_impl_sys_csrand_get(void *dst, size_t outlen)
94 {
95 	if (rand_get(dst, outlen, true) != 0) {
96 		/* Is it the only error it should return ? entropy_sam
97 		 * can return -ETIMEDOUT for example
98 		 */
99 		return -EIO;
100 	}
101 
102 	return 0;
103 }
104 
105 #endif /* CONFIG_HARDWARE_DEVICE_CS_GENERATOR */
106