Add CC13xx/CC26xx TRNG driver
This commit is contained in:
parent
adfeaa5500
commit
bb4056903c
2 changed files with 450 additions and 0 deletions
315
cpu/cc26xx-cc13xx/dev/soc-trng.c
Normal file
315
cpu/cc26xx-cc13xx/dev/soc-trng.c
Normal file
|
@ -0,0 +1,315 @@
|
|||
/*
|
||||
* Copyright (c) 2016, University of Bristol - http://www.bristol.ac.uk
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \addtogroup cc26xx-trng
|
||||
* @{
|
||||
*
|
||||
* \file
|
||||
*
|
||||
* Implementation of the CC13xx/CC26xx RNG driver
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include "contiki.h"
|
||||
#include "lpm.h"
|
||||
#include "sys/process.h"
|
||||
#include "dev/soc-trng.h"
|
||||
#include "ti-lib.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifdef SOC_TRNG_CONF_CACHE_LEN
|
||||
#define SOC_TRNG_CACHE_LEN SOC_TRNG_CONF_CACHE_LEN
|
||||
#else
|
||||
/** Size of the random number cache. Each slot holds 4 16-bit numbers */
|
||||
#define SOC_TRNG_CACHE_LEN 4
|
||||
#endif
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define MIN_REFILL_CYCLES_MAX 0x00000000
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS(soc_trng_process, "CC13xx/CC26xx TRNG process");
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static process_event_t rng_ready_event = PROCESS_EVENT_NONE;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static soc_trng_callback_t notify_cb = NULL;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define soc_trng_isr TRNGIntHandler
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint64_t rands_cache[SOC_TRNG_CACHE_LEN];
|
||||
static bool rands_mask[SOC_TRNG_CACHE_LEN];
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
disable_number_ready_interrupt(void)
|
||||
{
|
||||
ti_lib_trng_int_disable(TRNG_NUMBER_READY);
|
||||
ti_lib_rom_int_disable(INT_TRNG);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
enable_number_ready_interrupt(void)
|
||||
{
|
||||
ti_lib_trng_int_clear(TRNG_NUMBER_READY);
|
||||
ti_lib_trng_int_enable(TRNG_NUMBER_READY);
|
||||
ti_lib_rom_int_enable(INT_TRNG);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static bool
|
||||
accessible(void)
|
||||
{
|
||||
/* First, check the PD */
|
||||
if(ti_lib_rom_prcm_power_domain_status(PRCM_DOMAIN_PERIPH)
|
||||
!= PRCM_DOMAIN_POWER_ON) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Then check the 'run mode' clock gate */
|
||||
if(!(HWREG(PRCM_BASE + PRCM_O_SECDMACLKGR) &
|
||||
PRCM_SECDMACLKGDS_TRNG_CLK_EN_M)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
power_up(void)
|
||||
{
|
||||
/* First, make sure the PERIPH PD is on */
|
||||
ti_lib_rom_prcm_power_domain_on(PRCM_DOMAIN_PERIPH);
|
||||
while((ti_lib_rom_prcm_power_domain_status(PRCM_DOMAIN_PERIPH)
|
||||
!= PRCM_DOMAIN_POWER_ON));
|
||||
|
||||
/* Enable clock in active mode */
|
||||
ti_lib_rom_prcm_peripheral_run_enable(PRCM_PERIPH_TRNG);
|
||||
ti_lib_prcm_load_set();
|
||||
while(!ti_lib_prcm_load_get());
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
reset_synchronous(void)
|
||||
{
|
||||
ti_lib_trng_reset();
|
||||
while(HWREG(TRNG_BASE + TRNG_O_SWRESET));
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint8_t
|
||||
request(void)
|
||||
{
|
||||
if(notify_cb) {
|
||||
return LPM_MODE_SLEEP;
|
||||
}
|
||||
return LPM_MODE_MAX_SUPPORTED;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
LPM_MODULE(rng_module, request, NULL, NULL, LPM_DOMAIN_NONE);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static uint64_t
|
||||
read_number(void)
|
||||
{
|
||||
uint64_t ran = (uint64_t)HWREG(TRNG_BASE + TRNG_O_OUT1) << 32;
|
||||
ran += ti_lib_rom_trng_number_get(TRNG_LOW_WORD);
|
||||
|
||||
return ran;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint64_t
|
||||
soc_trng_rand_synchronous()
|
||||
{
|
||||
uint64_t ran;
|
||||
bool interrupts_disabled;
|
||||
int i;
|
||||
|
||||
/* If the TRNG is gathering entropy, return a cached value */
|
||||
if(notify_cb) {
|
||||
for(i = 0; i < SOC_TRNG_CACHE_LEN; i++) {
|
||||
if(rands_mask[i]) {
|
||||
rands_mask[i] = false;
|
||||
return rands_cache[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!accessible()) {
|
||||
power_up();
|
||||
}
|
||||
|
||||
/*
|
||||
* If we were previously enabled, we either have a number already available,
|
||||
* or we need clock, which means we are calculating. If neither is true then
|
||||
* we need setup from scratch.
|
||||
*/
|
||||
if((ti_lib_trng_status_get() & (TRNG_NEED_CLOCK | TRNG_NUMBER_READY)) == 0) {
|
||||
reset_synchronous();
|
||||
ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, SOC_TRNG_REFILL_CYCLES_MIN, 0);
|
||||
ti_lib_trng_enable();
|
||||
}
|
||||
|
||||
interrupts_disabled = ti_lib_int_master_disable();
|
||||
|
||||
while((ti_lib_trng_status_get() & TRNG_NUMBER_READY) == 0);
|
||||
|
||||
ran = read_number();
|
||||
|
||||
if(!interrupts_disabled) {
|
||||
ti_lib_int_master_enable();
|
||||
}
|
||||
|
||||
return ran;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint8_t
|
||||
soc_trng_rand_asynchronous(uint32_t samples, soc_trng_callback_t cb)
|
||||
{
|
||||
int i;
|
||||
bool interrupts_disabled;
|
||||
|
||||
if(notify_cb != NULL) {
|
||||
return SOC_TRNG_RAND_ASYNC_REQUEST_ERROR;
|
||||
}
|
||||
|
||||
if(!accessible()) {
|
||||
power_up();
|
||||
}
|
||||
|
||||
/*
|
||||
* First we need to cache some random numbers for general use in case the
|
||||
* application requests them while we are calculating.
|
||||
*
|
||||
* If we were previously enabled, we either have a number already available,
|
||||
* or we need clock, which means we are calculating. If neither is true then
|
||||
* we need setup from scratch.
|
||||
*/
|
||||
if((ti_lib_trng_status_get() & (TRNG_NEED_CLOCK | TRNG_NUMBER_READY)) == 0) {
|
||||
reset_synchronous();
|
||||
}
|
||||
|
||||
interrupts_disabled = ti_lib_int_master_disable();
|
||||
|
||||
ti_lib_trng_disable();
|
||||
ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, SOC_TRNG_REFILL_CYCLES_MIN, 0);
|
||||
ti_lib_trng_enable();
|
||||
|
||||
/* Cache SOC_TRNG_CACHE_LEN min-entropy rands */
|
||||
for(i = 0; i < SOC_TRNG_CACHE_LEN; i++) {
|
||||
while((ti_lib_trng_status_get() & TRNG_NUMBER_READY) == 0);
|
||||
rands_mask[i] = true;
|
||||
rands_cache[i] = read_number();
|
||||
}
|
||||
|
||||
/* Configure the RNG to the required entropy */
|
||||
ti_lib_trng_disable();
|
||||
ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, samples, 0);
|
||||
|
||||
/*
|
||||
* Clear the TRNG_NUMBER_READY flag. This will trigger a new calculation
|
||||
* as soon as the module gets enabled.
|
||||
*/
|
||||
ti_lib_trng_int_clear(TRNG_NUMBER_READY);
|
||||
|
||||
/* Enable clock in sleep mode and register with LPM */
|
||||
ti_lib_rom_prcm_peripheral_sleep_enable(PRCM_PERIPH_TRNG);
|
||||
ti_lib_prcm_load_set();
|
||||
while(!ti_lib_prcm_load_get());
|
||||
|
||||
lpm_register_module(&rng_module);
|
||||
|
||||
notify_cb = cb;
|
||||
|
||||
/* Enable the number ready interrupt and fire-up the module */
|
||||
enable_number_ready_interrupt();
|
||||
ti_lib_trng_enable();
|
||||
|
||||
if(!interrupts_disabled) {
|
||||
ti_lib_int_master_enable();
|
||||
}
|
||||
|
||||
return SOC_TRNG_RAND_ASYNC_REQUEST_OK;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
PROCESS_THREAD(soc_trng_process, ev, data)
|
||||
{
|
||||
PROCESS_BEGIN();
|
||||
|
||||
while(1) {
|
||||
PROCESS_YIELD_UNTIL(ev == rng_ready_event);
|
||||
|
||||
if(notify_cb) {
|
||||
uint64_t ran = read_number();
|
||||
|
||||
notify_cb(ran);
|
||||
notify_cb = NULL;
|
||||
}
|
||||
|
||||
/* Disable clock in sleep mode */
|
||||
ti_lib_rom_prcm_peripheral_sleep_disable(PRCM_PERIPH_TRNG);
|
||||
ti_lib_prcm_load_set();
|
||||
while(!ti_lib_prcm_load_get());
|
||||
|
||||
lpm_unregister_module(&rng_module);
|
||||
}
|
||||
|
||||
PROCESS_END();
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
soc_trng_isr(void)
|
||||
{
|
||||
ENERGEST_ON(ENERGEST_TYPE_IRQ);
|
||||
|
||||
ti_lib_trng_disable();
|
||||
|
||||
disable_number_ready_interrupt();
|
||||
|
||||
ti_lib_trng_configure(MIN_REFILL_CYCLES_MAX, SOC_TRNG_REFILL_CYCLES_MIN, 0);
|
||||
ti_lib_trng_enable();
|
||||
|
||||
process_post(&soc_trng_process, rng_ready_event, NULL);
|
||||
|
||||
ENERGEST_OFF(ENERGEST_TYPE_IRQ);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
soc_trng_init()
|
||||
{
|
||||
if(rng_ready_event != PROCESS_EVENT_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Register the RNG ready event */
|
||||
rng_ready_event = process_alloc_event();
|
||||
process_start(&soc_trng_process, NULL);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @}
|
||||
*/
|
135
cpu/cc26xx-cc13xx/dev/soc-trng.h
Normal file
135
cpu/cc26xx-cc13xx/dev/soc-trng.h
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2016, University of Bristol - http://www.bristol.ac.uk
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \addtogroup cc26xx
|
||||
* @{
|
||||
*
|
||||
* \defgroup cc26xx-trng CC13xx/CC26xx Random Number Generator
|
||||
*
|
||||
* Driver for the CC13xx/CC26xx Random Number Generator
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* \file
|
||||
*
|
||||
* Header file for the CC13xx/CC26xx TRNG driver
|
||||
*/
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#ifndef SOC_TRNG_H_
|
||||
#define SOC_TRNG_H_
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#include <stdint.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define SOC_TRNG_RAND_ASYNC_REQUEST_ERROR 0 /**< Async request rejected */
|
||||
#define SOC_TRNG_RAND_ASYNC_REQUEST_OK 1 /**< Async request accepted */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define SOC_TRNG_REFILL_CYCLES_MIN 0x00000100
|
||||
#define SOC_TRNG_REFILL_CYCLES_MAX 0x00000000
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \brief Pointer to a callback to be provided as an argument to
|
||||
* soc_trng_rand_asynchronous()
|
||||
*/
|
||||
typedef void (*soc_trng_callback_t)(uint64_t rand);
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* \name TRNG functions
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Returns a minimum entropy random number
|
||||
* \return The random number
|
||||
*
|
||||
* This function is synchronous. This function will make sure the PERIPH PD is
|
||||
* powered and the TRNG is clocked. The function will then configure the TRNG
|
||||
* to generate a random number of minimum entropy. These numbers are not
|
||||
* suitable for cryptographic usage, but their generation is very fast.
|
||||
*
|
||||
* If a high-entropy random number is currently being generated, this function
|
||||
* will return a cached random number. The cache is of configurable size and
|
||||
* can hold a maximum SOC_TRNG_CONF_CACHE_LEN numbers. If the cache gets
|
||||
* emptied while high-entropy generation is in progress (e.g. because a
|
||||
* function requested many random numbers in a row), this function will return
|
||||
* 0. Care must therefore be taken when the return value is 0, which can also
|
||||
* be a valid random number.
|
||||
*
|
||||
* This function can be safely called from within an interrupt context.
|
||||
*/
|
||||
uint64_t soc_trng_rand_synchronous();
|
||||
|
||||
/**
|
||||
* \brief Initialise the CC13xx/CC26xx TRNG driver
|
||||
*/
|
||||
void soc_trng_init(void);
|
||||
|
||||
/**
|
||||
* \brief Request a 64-bit, configurable-entropy random number
|
||||
* \param samples Controls the entropy generated for the random number
|
||||
* \param cb A callback function to be called when the generation is complete
|
||||
* \retval SOC_TRNG_RAND_ASYNC_REQUEST_ERROR There was an error adding request.
|
||||
* \retval SOC_TRNG_RAND_ASYNC_REQUEST_OK Request successfully registered
|
||||
*
|
||||
* This function is asynchronous, it will start generation of a random number
|
||||
* and will return. The caller must provide a callback that will be called when
|
||||
* the generation is complete. This callback must either use the random number
|
||||
* immediately or store it, since it will not be possible to retrieve it again
|
||||
* later form the soc-trng module.
|
||||
*
|
||||
* Only one generation can be active at any given point in time. If this
|
||||
* function gets called when a generation is already in progress, it will
|
||||
* return SOC_TRNG_RAND_ASYNC_REQUEST_ERROR.
|
||||
*
|
||||
* The function will configure the TRNG to generate entropy by sampling the
|
||||
* FROs for a number clock cycles controlled by the samples argument. The 8 LS
|
||||
* bits of this argument will be truncated by CC13xxware/CC26xxware and the
|
||||
* resulting number of clock cycles will be (samples >> 8) * 2^8. Increasing
|
||||
* the value of this argument increases entropy, but it also increases latency.
|
||||
* Maximum entropy can be generated by passing SOC_TRNG_REFILL_CYCLES_MAX, but
|
||||
* this will take approximately 350ms. Consult the chip's technical reference
|
||||
* manual for advice on what would constitute sufficient entropy for random
|
||||
* numbers meant to be used for crypto.
|
||||
*
|
||||
* While this function is executing, calls to soc_trng_rand_synchronous() will
|
||||
* return cached random numbers.
|
||||
*
|
||||
* This function is not re-entrant and must not be called from an interrupt
|
||||
* context.
|
||||
*/
|
||||
uint8_t soc_trng_rand_asynchronous(uint32_t samples, soc_trng_callback_t cb);
|
||||
/** @} */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#endif /* SOC_TRNG_H_ */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
*/
|
Loading…
Reference in a new issue