diff options
Diffstat (limited to 'drivers/nxp/crypto/caam/src/rng.c')
-rw-r--r-- | drivers/nxp/crypto/caam/src/rng.c | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/drivers/nxp/crypto/caam/src/rng.c b/drivers/nxp/crypto/caam/src/rng.c new file mode 100644 index 0000000..0b9d87d --- /dev/null +++ b/drivers/nxp/crypto/caam/src/rng.c @@ -0,0 +1,251 @@ +/* + * Copyright 2021 NXP + * + * SPDX-License-Identifier: BSD-3-Clause + * + */ + +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#include <arch_helpers.h> +#include "caam.h" +#include <common/debug.h> +#include "jobdesc.h" +#include "sec_hw_specific.h" + + +/* Callback function after Instantiation decsriptor is submitted to SEC */ +static void rng_done(uint32_t *desc, uint32_t status, void *arg, + void *job_ring) +{ + INFO("RNG Desc SUCCESS with status %x\n", status); +} + +/* Is the HW RNG instantiated? + * Return code: + * 0 - Not in the instantiated state + * 1 - In the instantiated state + * state_handle - 0 for SH0, 1 for SH1 + */ +static int is_hw_rng_instantiated(uint32_t *state_handle) +{ + int ret_code = 0; + uint32_t rdsta; + + rdsta = sec_in32(get_caam_addr() + RNG_REG_RDSTA_OFFSET); + + /*Check if either of the two state handles has been instantiated */ + if (rdsta & RNG_STATE0_HANDLE_INSTANTIATED) { + *state_handle = 0; + ret_code = 1; + } else if (rdsta & RNG_STATE0_HANDLE_INSTANTIATED) { + *state_handle = 1; + ret_code = 1; + } + + return ret_code; +} + +/* @brief Kick the TRNG block of the RNG HW Engine + * @param [in] ent_delay Entropy delay to be used + * By default, the TRNG runs for 200 clocks per sample; + * 1200 clocks per sample generates better entropy. + * @retval 0 on success + * @retval -1 on error + */ +static void kick_trng(int ent_delay) +{ + uint32_t val; + + /* put RNG4 into program mode */ + val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET); + val = val | RTMCTL_PRGM; + sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val); + + /* rtsdctl bits 0-15 contain "Entropy Delay, which defines the + * length (in system clocks) of each Entropy sample taken + */ + val = sec_in32(get_caam_addr() + RNG_REG_RTSDCTL_OFFSET); + val = (val & ~RTSDCTL_ENT_DLY_MASK) | + (ent_delay << RTSDCTL_ENT_DLY_SHIFT); + sec_out32(get_caam_addr() + RNG_REG_RTSDCTL_OFFSET, val); + /* min. freq. count, equal to 1/4 of the entropy sample length */ + sec_out32(get_caam_addr() + RNG_REG_RTFRQMIN_OFFSET, ent_delay >> 2); + /* disable maximum frequency count */ + sec_out32(get_caam_addr() + RNG_REG_RTFRQMAX_OFFSET, RTFRQMAX_DISABLE); + + /* select raw sampling in both entropy shifter + * and statistical checker + */ + val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET); + val = val | RTMCTL_SAMP_MODE_RAW_ES_SC; + sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val); + + /* put RNG4 into run mode */ + val = sec_in32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET); + val = val & ~RTMCTL_PRGM; + sec_out32(get_caam_addr() + RNG_REG_RTMCTL_OFFSET, val); +} + +/* @brief Submit descriptor to instantiate the RNG + * @retval 0 on success + * @retval -1 on error + */ +static int instantiate_rng(void) +{ + int ret = 0; + struct job_descriptor desc __aligned(CACHE_WRITEBACK_GRANULE); + struct job_descriptor *jobdesc = &desc; + + jobdesc->arg = NULL; + jobdesc->callback = rng_done; + + /* create the hw_rng descriptor */ + cnstr_rng_instantiate_jobdesc(jobdesc->desc); + + /* Finally, generate the requested random data bytes */ + ret = run_descriptor_jr(jobdesc); + if (ret != 0) { + ERROR("Error in running descriptor\n"); + ret = -1; + } + return ret; +} + +/* Generate Random Data using HW RNG + * Parameters: + * uint8_t* add_input - user specified optional input byte array + * uint32_t add_input_len - number of bytes of additional input + * uint8_t* out - user specified output byte array + * uint32_t out_len - number of bytes to store in output byte array + * Return code: + * 0 - SUCCESS + * -1 - ERROR + */ +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) +{ + int ret = 0; + struct job_descriptor desc __aligned(CACHE_WRITEBACK_GRANULE); + struct job_descriptor *jobdesc = &desc; + + jobdesc->arg = NULL; + jobdesc->callback = rng_done; + +#if defined(SEC_MEM_NON_COHERENT) && defined(IMAGE_BL2) + inv_dcache_range((uintptr_t)out, out_len); + dmbsy(); +#endif + + /* create the hw_rng descriptor */ + ret = cnstr_rng_jobdesc(jobdesc->desc, state_handle, + add_input, add_input_len, out, out_len); + if (ret != 0) { + ERROR("Descriptor construction failed\n"); + ret = -1; + goto out; + } + /* Finally, generate the requested random data bytes */ + ret = run_descriptor_jr(jobdesc); + if (ret != 0) { + ERROR("Error in running descriptor\n"); + ret = -1; + } + +out: + return ret; +} + +/* this function instantiates the rng + * + * Return code: + * 0 - All is well + * <0 - Error occurred somewhere + */ +int hw_rng_instantiate(void) +{ + int ret = 0; + int ent_delay = RTSDCTL_ENT_DLY_MIN; + uint32_t state_handle; + + ret = is_hw_rng_instantiated(&state_handle); + if (ret != 0) { + NOTICE("RNG already instantiated\n"); + return 0; + } + do { + kick_trng(ent_delay); + ent_delay += 400; + /*if instantiate_rng(...) fails, the loop will rerun + *and the kick_trng(...) function will modify the + *upper and lower limits of the entropy sampling + *interval, leading to a sucessful initialization of + */ + ret = instantiate_rng(); + } while ((ret == -1) && (ent_delay < RTSDCTL_ENT_DLY_MAX)); + if (ret != 0) { + ERROR("RNG: Failed to instantiate RNG\n"); + return ret; + } + + NOTICE("RNG: INSTANTIATED\n"); + + /* Enable RDB bit so that RNG works faster */ + // sec_setbits32(&sec->scfgr, SEC_SCFGR_RDBENABLE); + + return ret; +} + +/* Generate random bytes, and stuff them into the bytes buffer + * + * If the HW RNG has not already been instantiated, + * it will be instantiated before data is generated. + * + * Parameters: + * uint8_t* bytes - byte buffer large enough to hold the requested random date + * int byte_len - number of random bytes to generate + * + * Return code: + * 0 - All is well + * ~0 - Error occurred somewhere + */ +int get_rand_bytes_hw(uint8_t *bytes, int byte_len) +{ + int ret_code = 0; + uint32_t state_handle; + + /* If this is the first time this routine is called, + * then the hash_drbg will not already be instantiated. + * Therefore, before generating data, instantiate the hash_drbg + */ + ret_code = is_hw_rng_instantiated(&state_handle); + if (ret_code == 0) { + INFO("Instantiating the HW RNG\n"); + + /* Instantiate the hw RNG */ + ret_code = hw_rng_instantiate(); + if (ret_code != 0) { + ERROR("HW RNG Instantiate failed\n"); + return ret_code; + } + } + /* If HW RNG is still not instantiated, something must have gone wrong, + * it must be in the error state, we will not generate any random data + */ + if (is_hw_rng_instantiated(&state_handle) == 0) { + ERROR("HW RNG is in an Error state, and cannot be used\n"); + return -1; + } + /* Generate a random 256-bit value, as 32 bytes */ + ret_code = hw_rng_generate(0, 0, bytes, byte_len, state_handle); + if (ret_code != 0) { + ERROR("HW RNG Generate failed\n"); + return ret_code; + } + + return ret_code; +} |