Fix TRNG for NRF52

* When multiple TRNG objects are initialized, destroying the first
  object will turn the TRNG off for the other objects. This fix
  adds a counter to ensure that only when the last object is
  destroyed will it cause the TRNG to be disabled.

* The corner case where a user request 0 bytes is correctly handled
  and will now return immediately.
pull/6547/head
Marcus Chang 2018-02-17 21:20:06 -08:00
parent 5d5277336a
commit fa79e685fc
2 changed files with 58 additions and 23 deletions

View File

@ -37,21 +37,39 @@
*/
#if defined(DEVICE_TRNG)
#include "trng_api.h"
#include "hal/trng_api.h"
#include "hal/critical_section_api.h"
#include "nrf_drv_rng.h"
/* Keep track of instantiated FlashIAP objects. */
static int nordic_trng_counter = 0;
void trng_init(trng_t *obj)
{
(void) obj;
MBED_ASSERT(obj);
(void)nrf_drv_rng_init(NULL);
/* Increment global counter. */
nordic_trng_counter++;
/* Initialize TRNG on first object only. */
if (nordic_trng_counter == 1) {
nrf_drv_rng_init(NULL);
}
}
void trng_free(trng_t *obj)
{
(void) obj;
MBED_ASSERT(obj);
nrf_drv_rng_uninit();
/* Decrement global counter. */
nordic_trng_counter--;
/* Deinitialize TRNG when all objects have been freed. */
if (nordic_trng_counter == 0) {
nrf_drv_rng_uninit();
}
}
/* Get random data from NRF5x TRNG peripheral.
@ -61,30 +79,45 @@ void trng_free(trng_t *obj)
*/
int trng_get_bytes(trng_t *obj, uint8_t *output, size_t length, size_t *output_length)
{
uint8_t bytes_available;
MBED_ASSERT(obj);
MBED_ASSERT(output);
MBED_ASSERT(output_length);
(void) obj;
int result = 0;
nrf_drv_rng_bytes_available(&bytes_available);
/* Return immediately if requested length is zero. */
if (length != 0) {
if (bytes_available == 0) {
nrf_drv_rng_block_rand(output, 1);
*output_length = 1;
} else {
/* Query how many bytes are available. */
uint8_t bytes_available;
nrf_drv_rng_bytes_available(&bytes_available);
if (bytes_available > length) {
bytes_available = length;
}
if (nrf_drv_rng_rand(output, bytes_available) != NRF_SUCCESS) {
*output_length = 0;
return -1;
/* If no bytes are cached, block until at least 1 byte is available. */
if (bytes_available == 0) {
nrf_drv_rng_block_rand(output, 1);
*output_length = 1;
} else {
*output_length = bytes_available;
/* Get up to the requested number of bytes. */
if (bytes_available > length) {
bytes_available = length;
}
ret_code_t result = nrf_drv_rng_rand(output, bytes_available);
/* Set output length with available bytes. */
if (result == NRF_SUCCESS) {
*output_length = bytes_available;
} else {
*output_length = 0;
}
}
/* Set return value based on how many bytes were read. */
result = (*output_length == 0) ? -1 : 0;
}
return 0;
return result;
}
#endif

View File

@ -3508,6 +3508,7 @@
"ITM",
"TRNG",
"FLASH",
"TRNG",
"STCLK_OFF_DURING_SLEEP"
],
"extra_labels": [
@ -3541,7 +3542,7 @@
"supported_form_factors": ["ARDUINO"],
"inherits": ["MCU_NRF52832"],
"macros_add": ["BOARD_PCA10040", "NRF52_PAN_12", "NRF52_PAN_15", "NRF52_PAN_58", "NRF52_PAN_55", "NRF52_PAN_54", "NRF52_PAN_31", "NRF52_PAN_30", "NRF52_PAN_51", "NRF52_PAN_36", "NRF52_PAN_53", "S132", "CONFIG_GPIO_AS_PINRESET", "BLE_STACK_SUPPORT_REQD", "SWI_DISABLE0", "NRF52_PAN_20", "NRF52_PAN_64", "NRF52_PAN_62", "NRF52_PAN_63"],
"device_has_add": ["ANALOGIN", "I2C", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE", "TRNG"],
"device_has_add": ["ANALOGIN", "I2C", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPI_ASYNCH", "SPISLAVE"],
"release_versions": ["5"],
"device_name": "nRF52832_xxAA"
},
@ -3638,6 +3639,7 @@
"device_has": [
"ITM",
"FLASH",
"TRNG",
"STCLK_OFF_DURING_SLEEP"
],
"extra_labels": [
@ -3671,7 +3673,7 @@
"supported_form_factors": ["ARDUINO"],
"inherits": ["MCU_NRF52840"],
"macros_add": ["BOARD_PCA10056", "CONFIG_GPIO_AS_PINRESET", "SWI_DISABLE0", "NRF52_ERRATA_20"],
"device_has_add": ["ANALOGIN", "I2C", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "TRNG"],
"device_has_add": ["ANALOGIN", "I2C", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE"],
"release_versions": ["5"],
"device_name": "nRF52840_xxAA",
"bootloader_supported": true