samd/mcu: Implement a hardware seed for the SAMD21 random module.

By using the phase jitter between the DFLL48M clock and the FDPLL96M clock.
Even if both use the same reference source, they have a different jitter.
SysTick is driven by FDPLL96M, the us counter by DFLL48M.  As a random
source, the us counter is read out on every SysTick and the value is used
to accumulate a simple multiply, add and xor register.  According to tests
it creates about 30 bit random bit-flips per second.  That mechanism will
pass quite a few RNG tests, has a suitable frequency distribution and
serves better than just the time after boot to seed the PRNG.
pull/10664/head
robert-hh 2023-01-24 20:36:19 +01:00 zatwierdzone przez Damien George
rodzic 7e0b1bc95d
commit 76cf98c35b
4 zmienionych plików z 26 dodań i 4 usunięć

Wyświetl plik

@ -42,8 +42,10 @@ The :mod:`machine` module::
machine.freq(96_000_000) # set the CPU frequency to 96 MHz
The range accepted by the function call is 1_000_000 to 200_000_000 (1 MHz to 200 MHz)
for SAMD51 and 1_000_000 to 48_000_000 (1 MHz to 48 MHz) for SAMD21. The safe
range for SAMD51 according to the data sheet is 96 MHz to 120 MHz.
for SAMD51 and 1_000_000 to 54_000_000 (1 MHz to 54 MHz) for SAMD21. The safe
range for SAMD51 according to the data sheet is up to 120 MHz, for the SAMD21 up to 48Mhz.
Frequencies below 48Mhz are set by dividing 48Mhz by an integer, limiting the number of
discrete frequencies to 24Mhz, 16Mhz, 12MHz, and so on.
At frequencies below 8 MHz USB will be disabled. Changing the frequency below 48 MHz
impacts the baud rates of UART, I2C and SPI. These have to be set again after
changing the CPU frequency. The ms and µs timers are not affected by the frequency

Wyświetl plik

@ -78,8 +78,9 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
// CtrlB: Set the ref ource to GCLK, set the Wakup-Fast Flag.
SYSCTRL->DPLLCTRLB.reg = SYSCTRL_DPLLCTRLB_REFCLK_GCLK | SYSCTRL_DPLLCTRLB_WUF;
// Set the FDPLL ratio and enable the DPLL.
int ldr = cpu_freq_arg / FDPLL_REF_FREQ - 1;
SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDR(ldr);
int ldr = cpu_freq / FDPLL_REF_FREQ;
int frac = ((cpu_freq - ldr * FDPLL_REF_FREQ) / (FDPLL_REF_FREQ / 16)) & 0x0f;
SYSCTRL->DPLLRATIO.reg = SYSCTRL_DPLLRATIO_LDR((frac << 16 | ldr) - 1);
SYSCTRL->DPLLCTRLA.reg = SYSCTRL_DPLLCTRLA_ENABLE;
// Wait for the DPLL lock.
while (!SYSCTRL->DPLLSTATUS.bit.LOCK) {

Wyświetl plik

@ -22,6 +22,9 @@
#define MICROPY_PY_CMATH (0)
#endif
#define MICROPY_PY_URANDOM_SEED_INIT_FUNC (trng_random_u32())
unsigned long trng_random_u32(void);
#define VFS_BLOCK_SIZE_BYTES (1536) // 24x 64B flash pages;
#ifndef MICROPY_HW_UART_TXBUF

Wyświetl plik

@ -42,6 +42,9 @@ extern void EIC_Handler(void);
const ISR isr_vector[];
volatile uint32_t systick_ms;
volatile uint32_t ticks_us64_upper;
#if defined(MCU_SAMD21)
volatile uint32_t rng_state;
#endif
void Reset_Handler(void) __attribute__((naked));
void Reset_Handler(void) {
@ -91,6 +94,12 @@ void Default_Handler(void) {
}
void SysTick_Handler(void) {
#if defined(MCU_SAMD21)
// Use the phase jitter between the clocks to get some entropy
// and accumulate the random number register.
rng_state = (rng_state * 32310901 + 1) ^ (REG_TC4_COUNT32_COUNT >> 1);
#endif
uint32_t next_tick = systick_ms + 1;
systick_ms = next_tick;
@ -99,6 +108,13 @@ void SysTick_Handler(void) {
}
}
#if defined(MCU_SAMD21)
uint32_t trng_random_u32(void) {
mp_hal_delay_ms(320); // wait for ten cycles of the rng_seed register
return rng_state;
}
#endif
void us_timer_IRQ(void) {
#if defined(MCU_SAMD21)
if (TC4->COUNT32.INTFLAG.reg & TC_INTFLAG_OVF) {