1 /*
2  * Copyright 2021 NXP
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include <stdbool.h>
9 #include <stdint.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 
13 #include <arch_helpers.h>
14 #include "caam.h"
15 #include <common/debug.h>
16 #include "jobdesc.h"
17 #include "sec_hw_specific.h"
18 
19 
20 /* Callback function after Instantiation decsriptor is submitted to SEC */
rng_done(uint32_t * desc,uint32_t status,void * arg,void * job_ring)21 static void rng_done(uint32_t *desc, uint32_t status, void *arg,
22 		     void *job_ring)
23 {
24 	INFO("RNG Desc SUCCESS with status %x\n", status);
25 }
26 
27 /* Is the HW RNG instantiated?
28  * Return code:
29  * 0 - Not in the instantiated state
30  * 1 - In the instantiated state
31  * state_handle - 0 for SH0, 1 for SH1
32  */
is_hw_rng_instantiated(uint32_t * state_handle)33 static int is_hw_rng_instantiated(uint32_t *state_handle)
34 {
35 	int ret_code = 0;
36 	uint32_t rdsta;
37 
38 	rdsta = sec_in32(get_caam_addr() + RNG_REG_RDSTA_OFFSET);
39 
40 	 /*Check if either of the two state handles has been instantiated */
41 	if (rdsta & RNG_STATE0_HANDLE_INSTANTIATED) {
42 		*state_handle = 0;
43 		ret_code = 1;
44 	} else if (rdsta & RNG_STATE0_HANDLE_INSTANTIATED) {
45 		*state_handle = 1;
46 		ret_code = 1;
47 	}
48 
49 	return ret_code;
50 }
51 
52 /* @brief Kick the TRNG block of the RNG HW Engine
53  * @param [in] ent_delay       Entropy delay to be used
54  *        By default, the TRNG runs for 200 clocks per sample;
55  *        1200 clocks per sample generates better entropy.
56  * @retval 0 on success
57  * @retval -1 on error
58  */
kick_trng(int ent_delay)59 static void kick_trng(int ent_delay)
60 {
61 	uint32_t val;
62 
63 	/* put RNG4 into program mode */
64 	val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET);
65 	val = val | RTMCTL_PRGM;
66 	sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val);
67 
68 	/* rtsdctl bits 0-15 contain "Entropy Delay, which defines the
69 	 *  length (in system clocks) of each Entropy sample taken
70 	 */
71 	val = sec_in32(get_caam_addr() + RNG_REG_RTSDCTL_OFFSET);
72 	val = (val & ~RTSDCTL_ENT_DLY_MASK) |
73 	    (ent_delay << RTSDCTL_ENT_DLY_SHIFT);
74 	sec_out32(get_caam_addr() + RNG_REG_RTSDCTL_OFFSET, val);
75 	/* min. freq. count, equal to 1/4 of the entropy sample length */
76 	sec_out32(get_caam_addr() + RNG_REG_RTFRQMIN_OFFSET, ent_delay >> 2);
77 	/* disable maximum frequency count */
78 	sec_out32(get_caam_addr() + RNG_REG_RTFRQMAX_OFFSET, RTFRQMAX_DISABLE);
79 
80 	/* select raw sampling in both entropy shifter
81 	 *  and statistical checker
82 	 */
83 	val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET);
84 	val = val | RTMCTL_SAMP_MODE_RAW_ES_SC;
85 	sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val);
86 
87 	/* put RNG4 into run mode */
88 	val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET);
89 	val = val & ~RTMCTL_PRGM;
90 	sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val);
91 }
92 
93 /* @brief Submit descriptor to instantiate the RNG
94  * @retval 0 on success
95  * @retval -1 on error
96  */
instantiate_rng(void)97 static int instantiate_rng(void)
98 {
99 	int ret = 0;
100 	struct job_descriptor desc __aligned(CACHE_WRITEBACK_GRANULE);
101 	struct job_descriptor *jobdesc = &desc;
102 
103 	jobdesc->arg = NULL;
104 	jobdesc->callback = rng_done;
105 
106 	/* create the hw_rng descriptor */
107 	cnstr_rng_instantiate_jobdesc(jobdesc->desc);
108 
109 	/* Finally, generate the requested random data bytes */
110 	ret = run_descriptor_jr(jobdesc);
111 	if (ret != 0) {
112 		ERROR("Error in running descriptor\n");
113 		ret = -1;
114 	}
115 	return ret;
116 }
117 
118 /* Generate Random Data using HW RNG
119  * Parameters:
120  * uint8_t* add_input   - user specified optional input byte array
121  * uint32_t add_input_len - number of bytes of additional input
122  * uint8_t* out                   - user specified output byte array
123  * uint32_t out_len       - number of bytes to store in output byte array
124  * Return code:
125  * 0 - SUCCESS
126  * -1 - ERROR
127  */
128 static int
hw_rng_generate(uint32_t * add_input,uint32_t add_input_len,uint8_t * out,uint32_t out_len,uint32_t state_handle)129 hw_rng_generate(uint32_t *add_input, uint32_t add_input_len,
130 		uint8_t *out, uint32_t out_len, uint32_t state_handle)
131 {
132 	int ret = 0;
133 	struct job_descriptor desc __aligned(CACHE_WRITEBACK_GRANULE);
134 	struct job_descriptor *jobdesc = &desc;
135 
136 	jobdesc->arg = NULL;
137 	jobdesc->callback = rng_done;
138 
139 #if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2)
140 	inv_dcache_range((uintptr_t)out, out_len);
141 	dmbsy();
142 #endif
143 
144 	/* create the hw_rng descriptor */
145 	ret = cnstr_rng_jobdesc(jobdesc->desc, state_handle,
146 				add_input, add_input_len, out, out_len);
147 	if (ret != 0) {
148 		ERROR("Descriptor construction failed\n");
149 		ret = -1;
150 		goto out;
151 	}
152 	/* Finally, generate the requested random data bytes */
153 	ret = run_descriptor_jr(jobdesc);
154 	if (ret != 0) {
155 		ERROR("Error in running descriptor\n");
156 		ret = -1;
157 	}
158 
159 out:
160 	return ret;
161 }
162 
163 /* this function instantiates the rng
164  *
165  * Return code:
166  *  0 - All is well
167  * <0 - Error occurred somewhere
168  */
hw_rng_instantiate(void)169 int hw_rng_instantiate(void)
170 {
171 	int ret = 0;
172 	int ent_delay = RTSDCTL_ENT_DLY_MIN;
173 	uint32_t state_handle;
174 
175 	ret = is_hw_rng_instantiated(&state_handle);
176 	if (ret != 0) {
177 		NOTICE("RNG already instantiated\n");
178 		return 0;
179 	}
180 	do {
181 		kick_trng(ent_delay);
182 		ent_delay += 400;
183 		/*if instantiate_rng(...) fails, the loop will rerun
184 		 *and the kick_trng(...) function will modify the
185 		 *upper and lower limits of the entropy sampling
186 		 *interval, leading to a sucessful initialization of
187 		 */
188 		ret = instantiate_rng();
189 	} while ((ret == -1) && (ent_delay < RTSDCTL_ENT_DLY_MAX));
190 	if (ret != 0) {
191 		ERROR("RNG: Failed to instantiate RNG\n");
192 		return ret;
193 	}
194 
195 	NOTICE("RNG: INSTANTIATED\n");
196 
197 	/* Enable RDB bit so that RNG works faster */
198 	// sec_setbits32(&sec->scfgr, SEC_SCFGR_RDBENABLE);
199 
200 	return ret;
201 }
202 
203 /* Generate random bytes, and stuff them into the bytes buffer
204  *
205  * If the HW RNG has not already been instantiated,
206  *  it will be instantiated before data is generated.
207  *
208  * Parameters:
209  * uint8_t* bytes  - byte buffer large enough to hold the requested random date
210  * int byte_len - number of random bytes to generate
211  *
212  * Return code:
213  *  0 - All is well
214  *  ~0 - Error occurred somewhere
215  */
get_rand_bytes_hw(uint8_t * bytes,int byte_len)216 int get_rand_bytes_hw(uint8_t *bytes, int byte_len)
217 {
218 	int ret_code = 0;
219 	uint32_t state_handle;
220 
221 	/* If this is the first time this routine is called,
222 	 *  then the hash_drbg will not already be instantiated.
223 	 * Therefore, before generating data, instantiate the hash_drbg
224 	 */
225 	ret_code = is_hw_rng_instantiated(&state_handle);
226 	if (ret_code == 0) {
227 		INFO("Instantiating the HW RNG\n");
228 
229 		/* Instantiate the hw RNG */
230 		ret_code = hw_rng_instantiate();
231 		if (ret_code != 0) {
232 			ERROR("HW RNG Instantiate failed\n");
233 			return ret_code;
234 		}
235 	}
236 	/* If  HW RNG is still not instantiated, something must have gone wrong,
237 	 * it must be in the error state, we will not generate any random data
238 	 */
239 	if (is_hw_rng_instantiated(&state_handle) == 0) {
240 		ERROR("HW RNG is in an Error state, and cannot be used\n");
241 		return -1;
242 	}
243 	/* Generate a random 256-bit value, as 32 bytes */
244 	ret_code = hw_rng_generate(0, 0, bytes, byte_len, state_handle);
245 	if (ret_code != 0) {
246 		ERROR("HW RNG Generate failed\n");
247 		return ret_code;
248 	}
249 
250 	return ret_code;
251 }
252