From 0ebdbfbc88852c15d96f1b751d5b5080d50f967e Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 20 Oct 2013 11:38:31 -0600 Subject: [PATCH] SAMA5 TRNG: Add a /dev/random driver based on the SAMA5D3 TRNG peripheral --- ChangeLog | 3 +- arch/arm/src/sama5/Kconfig | 1 + arch/arm/src/sama5/Make.defs | 4 + arch/arm/src/sama5/chip/sam_trng.h | 84 +++++++ arch/arm/src/sama5/sam_trng.c | 353 +++++++++++++++++++++++++++++ arch/arm/src/sama5/sam_trng.h | 75 ++++++ arch/arm/src/sama5/sam_wdt.c | 2 +- configs/sama5d3x-ek/README.txt | 16 ++ 8 files changed, 536 insertions(+), 2 deletions(-) create mode 100644 arch/arm/src/sama5/chip/sam_trng.h create mode 100644 arch/arm/src/sama5/sam_trng.c create mode 100644 arch/arm/src/sama5/sam_trng.h diff --git a/ChangeLog b/ChangeLog index 3c5e8a54ac..7454ddc65d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5827,4 +5827,5 @@ SAMA5 RTC driver (2013-10-19). * arch/arm/src/sama5/sam_wdt.c and .h: Add a SAMA5 watchdog timer drvier. Untested on initial check-in (2013-10-19). - + * arch/arm/src/sama5/sam_trng.c, sam_trng.h, and chip/sam_trng.h: Add + a /dev/random driver based on the SAMA5D3 TRNG peripheral (2013-10-20). diff --git a/arch/arm/src/sama5/Kconfig b/arch/arm/src/sama5/Kconfig index 8094c72b1f..2d71c1e85b 100644 --- a/arch/arm/src/sama5/Kconfig +++ b/arch/arm/src/sama5/Kconfig @@ -276,6 +276,7 @@ config SAMA5_TDES config SAMA5_TRNG bool "True Random Number Generator (TRNG)" default n + select DEV_RANDOM config SAMA5_ARM bool "Performance Monitor Unit (ARM)" diff --git a/arch/arm/src/sama5/Make.defs b/arch/arm/src/sama5/Make.defs index 5f9ada19e4..848cf4fb30 100644 --- a/arch/arm/src/sama5/Make.defs +++ b/arch/arm/src/sama5/Make.defs @@ -118,6 +118,10 @@ ifeq ($(CONFIG_SAMA5_WDT),y) CHIP_CSRCS += sam_wdt.c endif +ifeq ($(CONFIG_SAMA5_TRNG),y) +CHIP_CSRCS += sam_trng.c +endif + ifeq ($(CONFIG_SAMA5_SPI0),y) CHIP_CSRCS += sam_spi.c else diff --git a/arch/arm/src/sama5/chip/sam_trng.h b/arch/arm/src/sama5/chip/sam_trng.h new file mode 100644 index 0000000000..0dfeffe1d4 --- /dev/null +++ b/arch/arm/src/sama5/chip/sam_trng.h @@ -0,0 +1,84 @@ +/************************************************************************************ + * arch/arm/src/sama5/chip/sam_trng.h + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 NuttX 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 OWNER 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. + * + ************************************************************************************/ + +#ifndef __ARCH_ARM_SRC_SAMA5_CHIP_SAM_TRNG_H +#define __ARCH_ARM_SRC_SAMA5_CHIP_SAM_TRNG_H + +/************************************************************************************ + * Included Files + ************************************************************************************/ + +#include +#include "chip/sam_memorymap.h" + +/************************************************************************************ + * Pre-processor Definitions + ************************************************************************************/ +/* TRNG Register Offsets ************************************************************/ + +#define SAM_TRNG_CR_OFFSET 0x0000 /* Control Register */ +#define SAM_TRNG_IER_OFFSET 0x0010 /* Interrupt Enable Register */ +#define SAM_TRNG_IDR_OFFSET 0x0014 /* Interrupt Disable Register */ +#define SAM_TRNG_IMR_OFFSET 0x0018 /* Interrupt Mask Register */ +#define SAM_TRNG_ISR_OFFSET 0x001c /* Interrupt Status Register */ +#define SAM_TRNG_ODATA_OFFSET 0x0050 /* Output Data Register */ + +/* TRNG Register Addresses **********************************************************/ + +#define SAM_TRNG_CR (SAM_TRNG_VBASE+SAM_TRNG_CR_OFFSET) +#define SAM_TRNG_IER (SAM_TRNG_VBASE+SAM_TRNG_IER_OFFSET) +#define SAM_TRNG_IDR (SAM_TRNG_VBASE+SAM_TRNG_IDR_OFFSET) +#define SAM_TRNG_IMR (SAM_TRNG_VBASE+SAM_TRNG_IMR_OFFSET) +#define SAM_TRNG_ISR (SAM_TRNG_VBASE+SAM_TRNG_ISR_OFFSET) +#define SAM_TRNG_ODATA (SAM_TRNG_VBASE+SAM_TRNG_ODATA_OFFSET) + +/* TRNG Register Bit Definitions ****************************************************/ + +/* Control Register */ + +#define TRNG_CR_ENABLE (1 << 0) /* Bit 0: nables the TRNG */ +#define TRNG_CR_KEY_SHIFT (8) /* Bits 8-31: Security key */ +#define TRNG_CR_KEY_MASK (0xffffff << TRNG_CR_KEY_SHIFT) +# define TRNG_CR_KEY (0x524e47 << TRNG_CR_KEY_SHIFT) /* RNG in ASCII */ + +/* Interrupt Enable Register, Interrupt Disable Register, Interrupt Mask Register, + * and Interrupt Status Register + */ + +#define TRNG_INT_DATRDY (1 << 0) /* Bit 0: Data ready */ + +/* Output Data Register (32-bit output data) */ + +#endif /* __ARCH_ARM_SRC_SAMA5_CHIP_SAM_TRNG_H */ diff --git a/arch/arm/src/sama5/sam_trng.c b/arch/arm/src/sama5/sam_trng.c new file mode 100644 index 0000000000..f865d081db --- /dev/null +++ b/arch/arm/src/sama5/sam_trng.c @@ -0,0 +1,353 @@ +/**************************************************************************** + * arch/arm/src/sama5/sam_trng.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Derives, in part, from Max Holtzberg's STM32 RNG Nuttx driver: + * + * Copyright (C) 2012 Max Holtzberg. All rights reserved. + * Author: Max Holtzberg + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "up_arch.h" +#include "up_internal.h" + +#include "sam_periphclks.h" +#include "sam_trng.h" + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* Interrupts */ + +static int sam_interrupt(int irq, void *context); + +/* Character driver methods */ + +static ssize_t sam_read(struct file *filep, char *buffer, size_t); + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct trng_dev_s +{ + sem_t exclsem; /* Enforces exclusive access to the TRNG */ + sem_t waitsem; /* Wait for buffer full */ + uint32_t *samples; /* Current buffer being filled */ + size_t maxsamples; /* Size of the current buffer (in 32-bit words) */ + volatile size_t nsamples; /* Number of samples currently buffered */ + volatile bool first; /* The first random number must be handled differently */ +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct trng_dev_s g_trngdev; + +static const struct file_operations g_trngops = +{ + 0, /* open */ + 0, /* close */ + sam_read, /* read */ + 0, /* write */ + 0, /* seek */ + 0 /* ioctl */ +#ifndef CONFIG_DISABLE_POLL + ,0 /* poll */ +#endif +}; + +/**************************************************************************** + * Private functions + ****************************************************************************/ + +/**************************************************************************** + * Name: sam_interrupt + * + * Description: + * The TRNG interrupt handler + * + * Input Parameters: + * + * Returned Value: + * + * + ****************************************************************************/ + +static int sam_interrupt(int irq, void *context) +{ + uint32_t odata; + + /* Verify that sample data is available */ + + if ((getreg32(SAM_TRNG_ISR) & CONFIG_SAMA5_TRNG) == 0) + { + /* No? Then why are we here? */ + + return OK; + } + + /* Read the random sample */ + + odata = getreg32(SAM_TRNG_ODATA); + + /* As required by the FIPS PUB (Federal Information Processing Standard + * Publication) 140-2, the first random number generated after setting the + * RNGEN bit should not be used, but saved for comparison with the next + * generated random number. Each subsequent generated random number has to be + * compared with the previously generated number. The test fails if any two + * compared numbers are equal (continuous random number generator test). + */ + + if (g_trngdev.nsamples == 0) + { + /* This is the first sample we have taken. Save it for subsequent + * comparison. + */ + + g_trngdev.samples[0] = odata; + g_trngdev.nsamples = 1; + return OK; + } + + /* This is not the first sample. Check if the new sample differs from the + * preceding sample. + */ + + else if (odata == g_trngdev.samples[g_trngdev.nsamples - 1]) + { + /* Two ssamples with the same value. Discard this one and try again. */ + + return OK; + } + + /* The numbers differ. Have we discarded the first sample yet? */ + + if (g_trngdev.first) + { + /* No, discard it now by replacing it with the new sample */ + + g_trngdev.samples[0] = odata; + g_trngdev.nsamples = 1; + g_trngdev.first = false; + } + + /* Yes.. the first sample has been dicarded */ + + else + { + /* Add the new random number to the buffer */ + + g_trngdev.samples[g_trngdev.nsamples] = odata; + g_trngdev.nsamples++; + } + + /* Have all of the requested samples been saved? */ + + if (g_trngdev.nsamples == g_trngdev.maxsamples) + { + /* Yes.. disable any further interrupts */ + + putreg32(TRNG_INT_DATRDY, SAM_TRNG_IER); + + /* And wakeup the waiting read thread. */ + + sem_post(&g_trngdev.waitsem); + } + + return OK; +} + +/**************************************************************************** + * Name: sam_read + * + * Description: + * This is the standard, NuttX character driver read method + * + * Input Parameters: + * filep - The VFS file instance + * buffer - Buffer in which to return the random samples + * buflen - The length of the buffer + * + * Returned Value: + * + ****************************************************************************/ + +static ssize_t sam_read(struct file *filep, char *buffer, size_t buflen) +{ + ssize_t retval; + int ret; + + fvdbg("buffer=%p buflen=%d\n", buffer, (int)buflen); + + /* Get exclusive access to the TRNG harware */ + + if (sem_wait(&g_trngdev.exclsem) != OK) + { + /* This is probably -EINTR meaning that we were awakened by a signal */ + + return -errno; + } + + /* Save the buffer information. */ + + DEBUGASSERT(((uintptr_t)buffer & 3) == 0); + + g_trngdev.samples = (uint32_t*)buffer; + g_trngdev.maxsamples = buflen >> 2; + g_trngdev.nsamples = 0; + g_trngdev.first = true; + + /* Enable TRNG interrupts */ + + putreg32(TRNG_INT_DATRDY, SAM_TRNG_IER); + + /* Wait until the buffer is filled */ + + while (g_trngdev.nsamples < g_trngdev.maxsamples) + { + ret = sem_wait(&g_trngdev.waitsem); + + fvdbg("Awakened: nsamples=%d maxsamples=%d ret=%d\n", + g_trngdev.nsamples, g_trngdev.maxsamples, ret); + + if (ret < 0) + { + /* We must have been awakened by a signal */ + + if (g_trngdev.nsamples > 0) + { + break; + } + else + { + retval = -errno; + goto errout; + } + } + } + + /* Success... calculate the number of bytes to return */ + + retval = g_trngdev.nsamples << 2; + +errout: + + /* Disable TRNG interrupts */ + + putreg32(TRNG_INT_DATRDY, SAM_TRNG_IDR); + + /* Release our lock on the TRNG hardware */ + + sem_post(&g_trngdev.exclsem); + + fvdbg("Return %d\n", (int)retval); + return retval; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_rnginitialize + * + * Description: + * Initialize the TRNG hardware and register the /dev/randome driver. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void up_rnginitialize(void) +{ + int ret; + + fvdbg("Initializing TRNG hardware\n"); + + /* Initialize the device structure */ + + memset(&g_trngdev, 0, sizeof(struct trng_dev_s)); + sem_init(&g_trngdev.exclsem, 0, 1); + sem_init(&g_trngdev.waitsem, 0, 0); + + /* Enable clocking to the TRNG */ + + sam_trng_enableclk(); + + /* Initialize the TRNG interrupt */ + + if (irq_attach(SAM_IRQ_TRNG, sam_interrupt)) + { + fdbg("ERROR: Failed to attach to IRQ%d\n", SAM_IRQ_TRNG); + return; + } + + /* Disable the interrupts at the TRNG */ + + putreg32(TRNG_INT_DATRDY, SAM_TRNG_IDR); + + /* Register the character driver */ + + ret = register_driver("/dev/random", &g_trngops, 0644, NULL); + if (ret < 0) + { + fdbg("ERROR: Failed to register /dev/random\n"); + return; + } + + /* Enable the TRNG interrupt at the AIC */ + + up_enable_irq(SAM_IRQ_TRNG); +} diff --git a/arch/arm/src/sama5/sam_trng.h b/arch/arm/src/sama5/sam_trng.h new file mode 100644 index 0000000000..dd379edc39 --- /dev/null +++ b/arch/arm/src/sama5/sam_trng.h @@ -0,0 +1,75 @@ +/**************************************************************************** + * arch/arm/src/sama5/sam_trng.h + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 NuttX 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 OWNER 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. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_SAMA5_SAM_TRNG_H +#define __ARCH_ARM_SRC_SAMA5_SAM_TRNG_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include "chip.h" +#include "chip/sam_trng.h" + +#if defined(CONFIG_DEV_RANDOM) && defined(CONFIG_SAMA5_TRNG) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CONFIG_DEV_RANDOM && CONFIG_SAMA5_TRNG */ +#endif /* __ARCH_ARM_SRC_SAMA5_SAM_TRNG_H */ diff --git a/arch/arm/src/sama5/sam_wdt.c b/arch/arm/src/sama5/sam_wdt.c index 45adceded9..e8e61b11da 100644 --- a/arch/arm/src/sama5/sam_wdt.c +++ b/arch/arm/src/sama5/sam_wdt.c @@ -427,7 +427,7 @@ static int sam_getstatus(FAR struct watchdog_lowerhalf_s *lower, wdvdbg("Status :\n"); wdvdbg(" flags : %08x\n", status->flags); wdvdbg(" timeout : %d\n", status->timeout); - wdvdbg(" timeleft : %d\n", status->flags); + wdvdbg(" timeleft : %d\n", status->timeleft); return OK; } diff --git a/configs/sama5d3x-ek/README.txt b/configs/sama5d3x-ek/README.txt index 9ea5667520..66109e06ed 100644 --- a/configs/sama5d3x-ek/README.txt +++ b/configs/sama5d3x-ek/README.txt @@ -2226,6 +2226,22 @@ Configurations beware that the default version also disables the watchdog. You will need a special version of norboot with CONFIG_SAMA5_WDT=y. + 19. This example can be configured to enable the SAMA5 TRNG peripheral so + that it provides /dev/random. The following configuration will enable + the TRNG, /dev/random, and the simple test of /dev/random at + apps/examples/ranadom: + + System Type: + CONFIG_SAMA5_TRNG=y : Enable the TRNG peripheral + + Drivers (automatically selected): + CONFIG_DEV_RANDOM=y : Enable /dev/random + + Applications -> Examples + CONFIG_EXAMPLES_RANDOM=y : Enable apps/examples/random + CONFIG_EXAMPLES_MAXSAMPLES=64 : Default settings are probably OK + CONFIG_EXAMPLES_NSAMPLES=8 + STATUS: PCK FREQUENCY