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 descriptor is submitted to SEC */ 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 */ 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 */ 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 */ 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 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 */ 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 successful 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 */ 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