SAMA5 TRNG: /dev/random appears to be functional
This commit is contained in:
parent
0ebdbfbc88
commit
dbeee18171
@ -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 */
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user