1 /*
2  * SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "sdkconfig.h"
7 #include "bootloader_random.h"
8 #include "esp_cpu.h"
9 #include "soc/wdev_reg.h"
10 
11 #if SOC_LP_TIMER_SUPPORTED
12 #include "hal/lp_timer_hal.h"
13 #endif
14 
15 #ifndef BOOTLOADER_BUILD
16 #include "esp_random.h"
17 #include "esp_private/periph_ctrl.h"
18 
bootloader_fill_random(void * buffer,size_t length)19  __attribute__((weak)) void bootloader_fill_random(void *buffer, size_t length)
20 {
21     return esp_fill_random(buffer, length);
22 }
23 
24 #else
25 
26 #if !defined CONFIG_IDF_TARGET_ESP32S3
27   #if (defined CONFIG_IDF_TARGET_ESP32C6 || defined CONFIG_IDF_TARGET_ESP32H2)
28     #define RNG_CPU_WAIT_CYCLE_NUM (80 * 16) // Keep the byte sampling frequency in the ~62KHz range which has been
29                                              // tested.
30   #else
31     #define RNG_CPU_WAIT_CYCLE_NUM (80 * 32 * 2) /* extra factor of 2 is precautionary */
32   #endif
33 #else
34   #define RNG_CPU_WAIT_CYCLE_NUM (80 * 23) /* 45 KHz reading frequency is the maximum we have tested so far on S3 */
35 #endif
36 
bootloader_fill_random(void * buffer,size_t length)37  __attribute__((weak)) void bootloader_fill_random(void *buffer, size_t length)
38 {
39     uint8_t *buffer_bytes = (uint8_t *)buffer;
40     uint32_t random;
41     uint32_t start, now;
42 
43     assert(buffer != NULL);
44 
45     for (size_t i = 0; i < length; i++) {
46 #if SOC_LP_TIMER_SUPPORTED
47         random = REG_READ(WDEV_RND_REG);
48         start = esp_cpu_get_cycle_count();
49         do {
50             random ^= REG_READ(WDEV_RND_REG);
51             now = esp_cpu_get_cycle_count();
52         } while (now - start < RNG_CPU_WAIT_CYCLE_NUM);
53 
54         // XOR the RT slow clock, which is asynchronous, to add some entropy and improve
55         // the distribution
56         uint32_t current_rtc_timer_counter = (lp_timer_hal_get_cycle_count() & 0xFF);
57         random = random ^ current_rtc_timer_counter;
58 
59         buffer_bytes[i] = random & 0xFF;
60 #else
61         if (i == 0 || i % 4 == 0) { /* redundant check is for a compiler warning */
62             /* in bootloader with ADC feeding HWRNG, we accumulate 1
63                bit of entropy per 40 APB cycles (==80 CPU cycles.)
64 
65                To avoid reading the entire RNG hardware state out
66                as-is, we repeatedly read the RNG register and XOR all
67                values.
68             */
69             random = REG_READ(WDEV_RND_REG);
70             start = esp_cpu_get_cycle_count();
71             do {
72                 random ^= REG_READ(WDEV_RND_REG);
73                 now = esp_cpu_get_cycle_count();
74             } while (now - start < RNG_CPU_WAIT_CYCLE_NUM);
75         }
76         buffer_bytes[i] = random >> ((i % 4) * 8);
77 #endif
78     }
79 }
80 
81 #ifndef CONFIG_IDF_ENV_FPGA
82 
83 #else // CONFIG_IDF_ENV_FPGA
84 #include "esp_log.h"
85 
s_non_functional(const char * func)86 static void s_non_functional(const char *func)
87 {
88     ESP_EARLY_LOGW("rand", "%s non-functional for FPGA builds", func);
89 }
90 
bootloader_random_enable()91 void bootloader_random_enable()
92 {
93     s_non_functional(__func__);
94 }
95 
bootloader_random_disable()96 void bootloader_random_disable()
97 {
98     s_non_functional(__func__);
99 }
100 
101 #endif // CONFIG_IDF_ENV_FPGA
102 
103 #endif // BOOTLOADER_BUILD
104