summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-10-20 12:08:39 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-10-20 12:08:39 -0600
commit7aa8e49278d649e46a79be8c8d2e609876a39b82 (patch)
tree1a5360552fb4d13015b29359292c99230e802578
parent6de05c200c43f0b41e454d14a0e856797718e769 (diff)
downloadnuttx-7aa8e49278d649e46a79be8c8d2e609876a39b82.tar.gz
nuttx-7aa8e49278d649e46a79be8c8d2e609876a39b82.tar.bz2
nuttx-7aa8e49278d649e46a79be8c8d2e609876a39b82.zip
SAMA5 TRNG: /dev/random appears to be functional
-rw-r--r--nuttx/arch/arm/src/sama5/chip/sam_trng.h3
-rw-r--r--nuttx/arch/arm/src/sama5/sam_trng.c144
2 files changed, 92 insertions, 55 deletions
diff --git a/nuttx/arch/arm/src/sama5/chip/sam_trng.h b/nuttx/arch/arm/src/sama5/chip/sam_trng.h
index 0dfeffe1d..15ac49cb1 100644
--- a/nuttx/arch/arm/src/sama5/chip/sam_trng.h
+++ b/nuttx/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/nuttx/arch/arm/src/sama5/sam_trng.c b/nuttx/arch/arm/src/sama5/sam_trng.c
index f865d081d..c93393bbe 100644
--- a/nuttx/arch/arm/src/sama5/sam_trng.c
+++ b/nuttx/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 */
+ /* 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 ((getreg32(SAM_TRNG_ISR) & CONFIG_SAMA5_TRNG) == 0)
+ for (;;)
{
- /* No? Then why are we here? */
+ /* Read the random sample (before checking DATRDY -- but probably not
+ * necessary)
+ */
- return OK;
- }
+ odata = getreg32(SAM_TRNG_ODATA);
- /* Read the random sample */
+ /* Verify that sample data is available (DATARDY is cleared when the
+ * interrupt status regiser is read)
+ */
- odata = getreg32(SAM_TRNG_ODATA);
+ if ((getreg32(SAM_TRNG_ISR) & TRNG_INT_DATRDY) == 0)
+ {
+ /* No? Then return and continue processing on the next interrupt. */
- /* 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).
- */
+ return OK;
+ }
- if (g_trngdev.nsamples == 0)
- {
- /* This is the first sample we have taken. Save it for subsequent
- * comparison.
+ /* 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).
*/
- g_trngdev.samples[0] = odata;
- g_trngdev.nsamples = 1;
- return OK;
- }
+ if (g_trngdev.nsamples == 0)
+ {
+ /* This is the first sample we have taken. Save it for subsequent
+ * comparison.
+ */
- /* This is not the first sample. Check if the new sample differs from the
- * preceding sample.
- */
+ 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;
+ }
- /* The numbers differ. Have we discarded the first sample yet? */
+ /* 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 */
+ 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;
- }
+ g_trngdev.samples[0] = odata;
+ g_trngdev.nsamples = 1;
+ g_trngdev.first = false;
+ }
- /* Yes.. the first sample has been dicarded */
+ /* Yes.. the first sample has been dicarded */
- else
- {
- /* Add the new random number to the buffer */
+ else
+ {
+ /* Add the new random number to the buffer */
- g_trngdev.samples[g_trngdev.nsamples] = odata;
- g_trngdev.nsamples++;
- }
+ g_trngdev.samples[g_trngdev.nsamples] = odata;
+ g_trngdev.nsamples++;
+ }
- /* Have all of the requested samples been saved? */
+ /* Have all of the requested samples been saved? */
- if (g_trngdev.nsamples == g_trngdev.maxsamples)
- {
- /* Yes.. disable any further interrupts */
+ if (g_trngdev.nsamples == g_trngdev.maxsamples)
+ {
+ /* Yes.. disable any further interrupts */
- putreg32(TRNG_INT_DATRDY, SAM_TRNG_IER);
+ putreg32(TRNG_INT_DATRDY, SAM_TRNG_IDR);
- /* And wakeup the waiting read thread. */
+ /* Disable the TRNG */
- sem_post(&g_trngdev.waitsem);
- }
+ putreg32(TRNG_CR_DISABLE | TRNG_CR_KEY, SAM_TRNG_CR);
- return OK;
+ /* 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);