Skip to content

Commit 01ee673

Browse files
Protect the HW random generation from FreeRTOS (#1395)
Fixes #1394 The Pico_Rand SDK calls gather bits from the HW ROSC at precise intervals. If there is jitter in the sleep_until() call then the ROSC bit collection will always think it's failed to acquire the right bit and retry infintitely. Avoid by wrapping the HW random number calls and the sleep_until() routine. Only when in FreeRTOS set a flag to silently make sleep_until() into a busy wait loop while in a random number generation step. When not in the random code, do the normal sleep_until call.
1 parent 5a94944 commit 01ee673

File tree

3 files changed

+48
-1
lines changed

3 files changed

+48
-1
lines changed

cores/rp2040/_freertos.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "_freertos.h"
2222
#include "pico/mutex.h"
2323
#include <stdlib.h>
24+
#include "Arduino.h"
2425

2526
typedef struct {
2627
mutex_t *src;
@@ -59,3 +60,45 @@ SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive) {
5960
}
6061
return nullptr; // Need to make space for more mutex maps!
6162
}
63+
64+
65+
// The HW Random code needs a precise sleep_until() in order to assure it
66+
// grabs the ROSC bit when it wants. Unfortunately, under FreeRTOS the
67+
// sleep_until() becomes imprecise and the "did I get the bit when I wanted"
68+
// check in the pico_rand code always fails and you get an infinite loop.
69+
70+
// This block wraps the 2 get_rand calls to set a flag to convert
71+
// sleep_until() (which can do a task swap and cause bad timing) into a
72+
// busy wait.
73+
74+
extern "C" {
75+
static bool __inRand = false;
76+
77+
extern uint64_t __real_get_rand_64();
78+
uint64_t __wrap_get_rand_64() {
79+
if (__isFreeRTOS) {
80+
rp2040.idleOtherCore();
81+
__inRand = true;
82+
auto r = __real_get_rand_64();
83+
__inRand = false;
84+
rp2040.resumeOtherCore();
85+
return r;
86+
} else {
87+
return __real_get_rand_64();
88+
}
89+
}
90+
91+
uint32_t __wrap_get_rand_32() {
92+
return (uint32_t) __wrap_get_rand_64();
93+
}
94+
95+
extern void __real_sleep_until(absolute_time_t t);
96+
void __wrap_sleep_until(absolute_time_t t) {
97+
if (__inRand) {
98+
busy_wait_until(t);
99+
} else {
100+
__real_sleep_until(t);
101+
}
102+
}
103+
104+
}

lib/platform_wrap.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,3 +207,7 @@
207207
-Wl,--wrap=cyw43_tcpip_link_status
208208
-Wl,--wrap=cyw43_cb_tcpip_init
209209
-Wl,--wrap=cyw43_cb_tcpip_deinit
210+
211+
-Wl,--wrap=get_rand_64
212+
-Wl,--wrap=get_rand_32
213+
-Wl,--wrap=sleep_until

tests/restyle.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S ./libraries/SingleF
1010
./libraries/Updater ./libraries/HTTPClient ./libraries/HTTPUpdate \
1111
./libraries/WebServer ./libraries/HTTPUpdateServer ./libraries/DNSServer \
1212
./libraries/Joystick ./libraries/Keyboard ./libraries/Mouse \
13-
./libraries/JoystickBT ./libraries/KeyboardBT ./variants ./libraries/BTstack \
13+
./libraries/JoystickBT ./libraries/KeyboardBT ./variants ./libraries/BTstackLib \
1414
./libraries/MouseBT ./libraries/SerialBT ./libraries/HID_Bluetooth \
1515
./libraries/JoystickBLE ./libraries/KeyboardBLE ./libraries/MouseBLE ; do
1616
find $dir -type f \( -name "*.c" -o -name "*.h" -o -name "*.cpp" \) -a \! -path '*api*' -exec astyle --suffix=none --options=./tests/astyle_core.conf \{\} \;

0 commit comments

Comments
 (0)