Skip to content

Commit d65f8e3

Browse files
mathieuchopstmkartben
authored andcommitted
drivers: entropy: stm32: don't waste generated random data
Even though the STM32 TRNG hardware produces 2- or 4-byte sized words of random data before triggering an interrupt, the driver currently discards all but the bottom byte: 50/75% of the produced entropy goes to waste! Make sure we consume all the random data from each word we read to improve the entropy generation rate seen by users of the driver. Signed-off-by: Mathieu Choplain <[email protected]>
1 parent abad49b commit d65f8e3

File tree

2 files changed

+63
-30
lines changed

2 files changed

+63
-30
lines changed

drivers/entropy/entropy_stm32.c

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
*
77
* SPDX-License-Identifier: Apache-2.0
88
*/
9+
#include <stddef.h>
910
#include <zephyr/kernel.h>
1011
#include <zephyr/device.h>
1112
#include <zephyr/drivers/entropy.h>
@@ -338,7 +339,7 @@ static int recover_seed_error(RNG_TypeDef *rng)
338339
}
339340
#endif /* !STM32_CONDRST_SUPPORT */
340341

341-
static int random_byte_get(void)
342+
static int random_sample_get(rng_sample_t *rnd_sample)
342343
{
343344
int retval = -EAGAIN;
344345
unsigned int key;
@@ -368,16 +369,16 @@ static int random_byte_get(void)
368369
goto out;
369370
}
370371

371-
retval = ll_rng_read_rand_data(rng);
372-
if (retval == 0) {
372+
*rnd_sample = ll_rng_read_rand_data(rng);
373+
if (*rnd_sample == 0) {
373374
/* A seed error could have occurred between RNG_SR
374375
* polling and RND_DR output reading.
375376
*/
376377
retval = -EAGAIN;
377378
goto out;
378379
}
379380

380-
retval &= 0xFF;
381+
retval = 0;
381382
}
382383

383384
out:
@@ -390,6 +391,8 @@ static int random_byte_get(void)
390391
static uint16_t generate_from_isr(uint8_t *buf, uint16_t len)
391392
{
392393
uint16_t remaining_len = len;
394+
rng_sample_t rnd_sample;
395+
int ret;
393396

394397
#if !IRQLESS_TRNG
395398
__ASSERT_NO_MSG(!irq_is_enabled(IRQN));
@@ -403,7 +406,7 @@ static uint16_t generate_from_isr(uint8_t *buf, uint16_t len)
403406
if (ll_rng_is_active_secs(entropy_stm32_rng_data.rng) ||
404407
ll_rng_is_active_seis(entropy_stm32_rng_data.rng)) {
405408

406-
(void)random_byte_get(); /* this will recover the error */
409+
(void)random_sample_get(&rnd_sample); /* this will recover the error */
407410

408411
return 0; /* return cnt is null : no random data available */
409412
}
@@ -418,8 +421,6 @@ static uint16_t generate_from_isr(uint8_t *buf, uint16_t len)
418421
#endif /* !IRQLESS_TRNG */
419422

420423
do {
421-
int byte;
422-
423424
while (ll_rng_is_active_drdy(
424425
entropy_stm32_rng_data.rng) != 1) {
425426
#if !IRQLESS_TRNG
@@ -441,16 +442,23 @@ static uint16_t generate_from_isr(uint8_t *buf, uint16_t len)
441442
#endif /* !IRQLESS_TRNG */
442443
}
443444

444-
byte = random_byte_get();
445+
ret = random_sample_get(&rnd_sample);
445446
#if !IRQLESS_TRNG
446447
NVIC_ClearPendingIRQ(IRQN);
447448
#endif /* IRQLESS_TRNG */
448449

449-
if (byte < 0) {
450+
if (ret < 0) {
450451
continue;
451452
}
452453

453-
buf[--remaining_len] = byte;
454+
/* push each byte of the RNG sample in buffer */
455+
size_t i = sizeof(rnd_sample);
456+
457+
while (remaining_len && i) {
458+
buf[--remaining_len] = (uint8_t)(rnd_sample & 0xFFu);
459+
rnd_sample >>= 8;
460+
i--;
461+
}
454462
} while (remaining_len);
455463

456464
return len;
@@ -604,31 +612,47 @@ static void rng_pool_init(struct rng_pool *rngp, uint16_t size,
604612

605613
static int perform_pool_refill(void)
606614
{
607-
int byte, ret;
615+
rng_sample_t rnd_sample;
616+
bool refilled_thr = false;
617+
int ret;
608618

609-
byte = random_byte_get();
610-
if (byte < 0) {
611-
return -EIO;
619+
ret = random_sample_get(&rnd_sample);
620+
if (ret < 0) {
621+
return ret;
612622
}
613623

614-
ret = rng_pool_put((struct rng_pool *)(entropy_stm32_rng_data.isr),
615-
byte);
616-
if (ret < 0) {
617-
ret = rng_pool_put(
618-
(struct rng_pool *)(entropy_stm32_rng_data.thr),
619-
byte);
624+
/* push each byte of the RNG sample in pools */
625+
for (size_t i = 0; i < sizeof(rnd_sample); i++, rnd_sample >>= 8) {
626+
uint8_t byte = rnd_sample & 0xFFu;
627+
628+
ret = rng_pool_put((struct rng_pool *)(entropy_stm32_rng_data.isr), byte);
620629
if (ret < 0) {
630+
/* Take note that data has been added to thread pool */
631+
refilled_thr = true;
632+
633+
ret = rng_pool_put((struct rng_pool *)(entropy_stm32_rng_data.thr), byte);
634+
if (ret < 0) {
621635
#if !IRQLESS_TRNG
622-
irq_disable(IRQN);
636+
irq_disable(IRQN);
623637
#endif /* !IRQLESS_TRNG */
624-
release_rng();
625-
pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES);
626-
if (IS_ENABLED(CONFIG_PM_S2RAM)) {
627-
pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM, PM_ALL_SUBSTATES);
638+
release_rng();
639+
pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE,
640+
PM_ALL_SUBSTATES);
641+
if (IS_ENABLED(CONFIG_PM_S2RAM)) {
642+
pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_RAM,
643+
PM_ALL_SUBSTATES);
644+
}
645+
entropy_stm32_rng_data.filling_pools = false;
646+
break;
628647
}
629-
entropy_stm32_rng_data.filling_pools = false;
630648
}
649+
}
631650

651+
if (refilled_thr) {
652+
/**
653+
* Wake up threads that may be waiting for new data to be
654+
* available in thread pool if we added entropy in it.
655+
*/
632656
k_sem_give(&entropy_stm32_rng_data.sem_sync);
633657
}
634658

@@ -645,7 +669,8 @@ static void trng_poll_work_item(struct k_work *work)
645669
if (ll_rng_is_active_secs(entropy_stm32_rng_data.rng) ||
646670
ll_rng_is_active_seis(entropy_stm32_rng_data.rng)) {
647671

648-
(void)random_byte_get(); /* this will recover the error */
672+
rng_sample_t dummy;
673+
(void)random_sample_get(&dummy); /* this will recover the error */
649674
} else if (ll_rng_is_active_drdy(rng)) {
650675
/* Entropy available: read it and fill pools */
651676
int res = perform_pool_refill();

drivers/entropy/entropy_stm32.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,18 @@ static inline uint32_t ll_rng_is_active_drdy(RNG_TypeDef *RNGx)
8888
#endif /* CONFIG_SOC_SERIES_STM32WB0X */
8989
}
9090

91-
static inline uint16_t ll_rng_read_rand_data(RNG_TypeDef *RNGx)
91+
#if defined(CONFIG_SOC_SERIES_STM32WB0X) && !defined(CONFIG_SOC_STM32WB09XX)
92+
/* STM32WB05, STM32WB06 and STM32WB07 have 16-bit data register */
93+
typedef uint16_t rng_sample_t;
94+
#else
95+
/* All other TRNG IPs have 32-bit data register */
96+
typedef uint32_t rng_sample_t;
97+
#endif
98+
99+
static inline rng_sample_t ll_rng_read_rand_data(RNG_TypeDef *RNGx)
92100
{
93101
#if defined(CONFIG_SOC_STM32WB09XX)
94-
uint16_t rnd = (uint16_t)LL_RNG_GetRndVal(RNGx);
102+
rng_sample_t rnd = LL_RNG_GetRndVal(RNGx);
95103

96104
/**
97105
* STM32WB09 TRNG does not clear IRQ flags in hardware.
@@ -108,6 +116,6 @@ static inline uint16_t ll_rng_read_rand_data(RNG_TypeDef *RNGx)
108116
/* STM32WB05 / STM32WB06 / STM32WB07 */
109117
return LL_RNG_ReadRandData16(RNGx);
110118
#else
111-
return (uint16_t)LL_RNG_ReadRandData32(RNGx);
119+
return LL_RNG_ReadRandData32(RNGx);
112120
#endif /* CONFIG_SOC_SERIES_STM32WB0X */
113121
}

0 commit comments

Comments
 (0)