From dbeee181717e0eddac1699bbd77eb4ac63bfa57b Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 20 Oct 2013 12:08:39 -0600 Subject: [PATCH] SAMA5 TRNG: /dev/random appears to be functional --- arch/arm/src/sama5/chip/sam_trng.h | 3 +- arch/arm/src/sama5/sam_trng.c | 174 +++++++++++++++++------------ 2 files changed, 107 insertions(+), 70 deletions(-) diff --git a/arch/arm/src/sama5/chip/sam_trng.h b/arch/arm/src/sama5/chip/sam_trng.h index 0dfeffe1d4..15ac49cb10 100644 --- a/arch/arm/src/sama5/chip/sam_trng.h +++ b/arch/arm/src/sama5/chip/sam_trng.h @@ -68,7 +68,8 @@ /* Control Register */ -#define TRNG_CR_ENABLE (1 << 0) /* Bit 0: nables the TRNG */ +#define TRNG_CR_ENABLE (1 << 0) /* Bit 0: 1=Enables the TRNG */ +# define TRNG_CR_DISABLE (0) /* Bit 0: 0=Disables 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 */ diff --git a/arch/arm/src/sama5/sam_trng.c b/arch/arm/src/sama5/sam_trng.c index f865d081db..c93393bbe1 100644 --- a/arch/arm/src/sama5/sam_trng.c +++ b/arch/arm/src/sama5/sam_trng.c @@ -125,84 +125,102 @@ 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). + /* Loop where there are samples available to be read and/or until the user + * buffer is filled. Each sample requires only 84 clocks it is likely + * that we will loop here. */ - if (g_trngdev.nsamples == 0) + for (;;) { - /* This is the first sample we have taken. Save it for subsequent - * comparison. + /* Read the random sample (before checking DATRDY -- but probably not + * necessary) */ - g_trngdev.samples[0] = odata; - g_trngdev.nsamples = 1; - return OK; - } + odata = getreg32(SAM_TRNG_ODATA); - /* This is not the first sample. Check if the new sample differs from the - * preceding sample. - */ + /* Verify that sample data is available (DATARDY is cleared when the + * interrupt status regiser is read) + */ + + if ((getreg32(SAM_TRNG_ISR) & TRNG_INT_DATRDY) == 0) + { + /* No? Then return and continue processing on the next interrupt. */ + + return OK; + } + + /* 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; + continue; + } + + /* 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. */ + else if (odata == g_trngdev.samples[g_trngdev.nsamples - 1]) + { + /* Two samples with the same value. Discard this one and try again. */ - return OK; + continue; + } + + /* This sample differs from the previous value. 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_IDR); + + /* Disable the TRNG */ + + putreg32(TRNG_CR_DISABLE | TRNG_CR_KEY, SAM_TRNG_CR); + + /* And wakeup the waiting read thread. */ + + sem_post(&g_trngdev.waitsem); + 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; } /**************************************************************************** @@ -245,6 +263,16 @@ static ssize_t sam_read(struct file *filep, char *buffer, size_t buflen) g_trngdev.nsamples = 0; g_trngdev.first = true; + /* Enable the TRNG */ + + putreg32(TRNG_CR_ENABLE | TRNG_CR_KEY, SAM_TRNG_CR); + + /* Clear any pending TRNG interrupts by reading the interrupt status + * register + */ + + (void)getreg32(SAM_TRNG_ISR); + /* Enable TRNG interrupts */ putreg32(TRNG_INT_DATRDY, SAM_TRNG_IER); @@ -284,6 +312,10 @@ errout: putreg32(TRNG_INT_DATRDY, SAM_TRNG_IDR); + /* Disable the TRNG */ + + putreg32(TRNG_CR_DISABLE | TRNG_CR_KEY, SAM_TRNG_CR); + /* Release our lock on the TRNG hardware */ sem_post(&g_trngdev.exclsem); @@ -338,6 +370,10 @@ void up_rnginitialize(void) putreg32(TRNG_INT_DATRDY, SAM_TRNG_IDR); + /* Disable the TRNG */ + + putreg32(TRNG_CR_DISABLE | TRNG_CR_KEY, SAM_TRNG_CR); + /* Register the character driver */ ret = register_driver("/dev/random", &g_trngops, 0644, NULL);