xref: /optee_os/core/drivers/stm32_rng.c (revision 097f329a1c27a4eabc87f4b6d457627832d6670b)
1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Copyright (c) 2018-2019, STMicroelectronics
4  */
5 
6 #include <assert.h>
7 #include <drivers/clk.h>
8 #include <drivers/clk_dt.h>
9 #include <drivers/stm32_rng.h>
10 #include <io.h>
11 #include <kernel/delay.h>
12 #include <kernel/dt.h>
13 #include <kernel/boot.h>
14 #include <kernel/panic.h>
15 #include <kernel/thread.h>
16 #include <libfdt.h>
17 #include <mm/core_memprot.h>
18 #include <rng_support.h>
19 #include <stdbool.h>
20 #include <stm32_util.h>
21 #include <string.h>
22 
23 #define DT_RNG_COMPAT		"st,stm32-rng"
24 #define RNG_CR			0x00U
25 #define RNG_SR			0x04U
26 #define RNG_DR			0x08U
27 
28 #define RNG_CR_RNGEN		BIT(2)
29 #define RNG_CR_IE		BIT(3)
30 #define RNG_CR_CED		BIT(5)
31 
32 #define RNG_SR_DRDY		BIT(0)
33 #define RNG_SR_CECS		BIT(1)
34 #define RNG_SR_SECS		BIT(2)
35 #define RNG_SR_CEIS		BIT(5)
36 #define RNG_SR_SEIS		BIT(6)
37 
38 #define RNG_TIMEOUT_US		U(100000)
39 
40 struct stm32_rng_instance {
41 	struct io_pa_va base;
42 	struct clk *clock;
43 	unsigned int lock;
44 	unsigned int refcount;
45 	bool release_post_boot;
46 };
47 
48 static struct stm32_rng_instance *stm32_rng;
49 
50 /*
51  * Extracts from the STM32 RNG specification:
52  *
53  * When a noise source (or seed) error occurs, the RNG stops generating
54  * random numbers and sets to “1” both SEIS and SECS bits to indicate
55  * that a seed error occurred. (...)
56 
57  * The following sequence shall be used to fully recover from a seed
58  * error after the RNG initialization:
59  * 1. Clear the SEIS bit by writing it to “0”.
60  * 2. Read out 12 words from the RNG_DR register, and discard each of
61  * them in order to clean the pipeline.
62  * 3. Confirm that SEIS is still cleared. Random number generation is
63  * back to normal.
64  */
65 static void conceal_seed_error(vaddr_t rng_base)
66 {
67 	if (io_read32(rng_base + RNG_SR) & (RNG_SR_SECS | RNG_SR_SEIS)) {
68 		size_t i = 0;
69 
70 		io_mask32(rng_base + RNG_SR, 0, RNG_SR_SEIS);
71 
72 		for (i = 12; i != 0; i--)
73 			(void)io_read32(rng_base + RNG_DR);
74 
75 		if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS)
76 			panic("RNG noise");
77 	}
78 }
79 
80 #define RNG_FIFO_BYTE_DEPTH		16u
81 
82 static TEE_Result read_available(vaddr_t rng_base, uint8_t *out, size_t *size)
83 {
84 	uint8_t *buf = NULL;
85 	size_t req_size = 0;
86 	size_t len = 0;
87 
88 	conceal_seed_error(rng_base);
89 
90 	if (!(io_read32(rng_base + RNG_SR) & RNG_SR_DRDY)) {
91 		FMSG("RNG not ready");
92 		return TEE_ERROR_NO_DATA;
93 	}
94 
95 	if (io_read32(rng_base + RNG_SR) & RNG_SR_SEIS) {
96 		FMSG("RNG noise error");
97 		return TEE_ERROR_NO_DATA;
98 	}
99 
100 	buf = out;
101 	req_size = MIN(RNG_FIFO_BYTE_DEPTH, *size);
102 	len = req_size;
103 
104 	/* RNG is ready: read up to 4 32bit words */
105 	while (len) {
106 		uint32_t data32 = io_read32(rng_base + RNG_DR);
107 		size_t sz = MIN(len, sizeof(uint32_t));
108 
109 		memcpy(buf, &data32, sz);
110 		buf += sz;
111 		len -= sz;
112 	}
113 
114 	*size = req_size;
115 
116 	return TEE_SUCCESS;
117 }
118 
119 static void gate_rng(bool enable, struct stm32_rng_instance *dev)
120 {
121 	vaddr_t rng_cr = io_pa_or_va(&dev->base, 1) + RNG_CR;
122 	uint32_t exceptions = may_spin_lock(&dev->lock);
123 
124 	if (enable) {
125 		/* incr_refcnt return non zero if resource shall be enabled */
126 		if (incr_refcnt(&dev->refcount)) {
127 			FMSG("enable RNG");
128 			clk_enable(dev->clock);
129 			io_write32(rng_cr, 0);
130 			io_write32(rng_cr, RNG_CR_RNGEN | RNG_CR_CED);
131 		}
132 	} else {
133 		/* decr_refcnt return non zero if resource shall be disabled */
134 		if (decr_refcnt(&dev->refcount)) {
135 			FMSG("disable RNG");
136 			io_write32(rng_cr, 0);
137 			clk_disable(dev->clock);
138 		}
139 	}
140 
141 	may_spin_unlock(&dev->lock, exceptions);
142 }
143 
144 TEE_Result stm32_rng_read(uint8_t *out, size_t size)
145 {
146 	TEE_Result rc = TEE_ERROR_GENERIC;
147 	bool burst_timeout = false;
148 	uint64_t timeout_ref = 0;
149 	uint32_t exceptions = 0;
150 	uint8_t *out_ptr = out;
151 	vaddr_t rng_base = 0;
152 	size_t out_size = 0;
153 
154 	if (!stm32_rng) {
155 		DMSG("No RNG");
156 		return TEE_ERROR_NOT_SUPPORTED;
157 	}
158 
159 	gate_rng(true, stm32_rng);
160 	rng_base = io_pa_or_va(&stm32_rng->base, 1);
161 
162 	/* Arm timeout */
163 	timeout_ref = timeout_init_us(RNG_TIMEOUT_US);
164 	burst_timeout = false;
165 
166 	while (out_size < size) {
167 		/* Read by chunks of the size the RNG FIFO depth */
168 		size_t sz = size - out_size;
169 
170 		exceptions = may_spin_lock(&stm32_rng->lock);
171 
172 		rc = read_available(rng_base, out_ptr, &sz);
173 
174 		/* Raise timeout only if we failed to get some samples */
175 		assert(!rc || rc == TEE_ERROR_NO_DATA);
176 		if (rc)
177 			burst_timeout = timeout_elapsed(timeout_ref);
178 
179 		may_spin_unlock(&stm32_rng->lock, exceptions);
180 
181 		if (burst_timeout) {
182 			rc = TEE_ERROR_GENERIC;
183 			goto out;
184 		}
185 
186 		if (!rc) {
187 			out_size += sz;
188 			out_ptr += sz;
189 			/* Re-arm timeout */
190 			timeout_ref = timeout_init_us(RNG_TIMEOUT_US);
191 			burst_timeout = false;
192 		}
193 	}
194 
195 out:
196 	assert(!rc || rc == TEE_ERROR_GENERIC);
197 	gate_rng(false, stm32_rng);
198 
199 	return rc;
200 }
201 
202 #ifndef CFG_WITH_SOFTWARE_PRNG
203 TEE_Result crypto_rng_read(void *out, size_t size)
204 {
205 	return stm32_rng_read(out, size);
206 }
207 
208 uint8_t hw_get_random_byte(void)
209 {
210 	uint8_t byte = 0;
211 
212 	if (stm32_rng_read(&byte, sizeof(byte)))
213 		panic();
214 
215 	return byte;
216 }
217 #endif
218 
219 #ifdef CFG_EMBED_DTB
220 static TEE_Result stm32_rng_init(void)
221 {
222 	void *fdt = NULL;
223 	int node = -1;
224 	struct dt_node_info dt_info;
225 	TEE_Result res = TEE_ERROR_GENERIC;
226 
227 	memset(&dt_info, 0, sizeof(dt_info));
228 
229 	fdt = get_embedded_dt();
230 	if (!fdt)
231 		panic();
232 
233 	while (true) {
234 		node = fdt_node_offset_by_compatible(fdt, node, DT_RNG_COMPAT);
235 		if (node < 0)
236 			break;
237 
238 		_fdt_fill_device_info(fdt, &dt_info, node);
239 
240 		if (!(dt_info.status & DT_STATUS_OK_SEC))
241 			continue;
242 
243 		if (stm32_rng)
244 			panic();
245 
246 		stm32_rng = calloc(1, sizeof(*stm32_rng));
247 		if (!stm32_rng)
248 			panic();
249 
250 		assert(dt_info.clock != DT_INFO_INVALID_CLOCK &&
251 		       dt_info.reg != DT_INFO_INVALID_REG &&
252 		       dt_info.reg_size != DT_INFO_INVALID_REG_SIZE);
253 
254 		if (dt_info.status & DT_STATUS_OK_NSEC) {
255 			stm32mp_register_non_secure_periph_iomem(dt_info.reg);
256 			stm32_rng->release_post_boot = true;
257 		} else {
258 			stm32mp_register_secure_periph_iomem(dt_info.reg);
259 		}
260 
261 		stm32_rng->base.pa = dt_info.reg;
262 		if (!io_pa_or_va_secure(&stm32_rng->base, dt_info.reg_size))
263 			panic();
264 
265 		res = clk_dt_get_by_index(fdt, node, 0, &stm32_rng->clock);
266 		if (res)
267 			return res;
268 
269 		assert(stm32_rng->clock);
270 
271 		DMSG("RNG init");
272 	}
273 
274 	return TEE_SUCCESS;
275 }
276 
277 early_init_late(stm32_rng_init);
278 
279 static TEE_Result stm32_rng_release(void)
280 {
281 	if (stm32_rng && stm32_rng->release_post_boot) {
282 		DMSG("Release RNG driver");
283 		assert(!stm32_rng->refcount);
284 		free(stm32_rng);
285 		stm32_rng = NULL;
286 	}
287 
288 	return TEE_SUCCESS;
289 }
290 
291 release_init_resource(stm32_rng_release);
292 #endif /*CFG_EMBED_DTB*/
293