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