blob: 0b9d87de41e2ed7affd62e9d6bd5d005aa91c60f [file] [log] [blame]
Pankaj Gupta95c7eee2020-12-09 14:02:39 +05301/*
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 */
21static 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 */
33static 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 */
59static 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 */
97static 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 */
128static int
129hw_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
159out:
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 */
169int 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 */
216int 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}