Skip to content

Commit 23755f0

Browse files
committed
Rewrite RNG
1 parent 8c64b09 commit 23755f0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+825
-420
lines changed

esp-hal/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- A reimplemntation of the `assign_resources!` macro (#3809)
13+
- `TrngSource` to manage random number generator entropy (#3829)
1314

1415
### Changed
1516

17+
- The `rng` module has been rewritten (#3829)
1618

1719
### Fixed
1820

@@ -21,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2123

2224
### Removed
2325

26+
- `Trng::new` (replaced by `Trng::try_new`) (#3829)
2427

2528
## [v1.0.0-rc.0] - 2025-07-16
2629

esp-hal/MIGRATING-1.0.0-rc.0.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Migration Guide from 1.0.0-rc.0 to {{currentVersion}}
2+
3+
## RNG changes
4+
5+
Random number generator objects can now be created anywhere. The `RNG` peripheral singleton
6+
is only necessary to enable the cryptographically secure random number generator.
7+
8+
- `Rng` can be constructed without any constraints.
9+
- `Trng` can only be constructed when it can be ensured to generate true random numbers.
10+
11+
A new `TrngSource` object has been added. Users can use `TrngSource::new` to create the object,
12+
and as long as it is alive, `Trng::try_new` will return `Ok` and will provide a true random number
13+
generator interface.
14+
15+
The previous way to obtain RNG object has changed like so:
16+
17+
```diff
18+
-let mut rng = Rng::new(peripherals.RNG);
19+
+let rng = Rng::new();
20+
21+
-let mut trng = Trng::new(peripherals.RNG, peripherals.ADC1);
22+
+// Once:
23+
+let trng_source = TrngSource::new(peripherals.RNG, peripherals.ADC1);
24+
+// As long as `trng_source` is alive:
25+
+let trng = Tnrg::try_new().unrwap();
26+
```

esp-hal/src/rng.rs

Lines changed: 0 additions & 271 deletions
This file was deleted.

esp-hal/src/rng/ll.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
use crate::{clock::Clocks, peripherals::RNG, sync::RawMutex};
2+
3+
static RNG_IN_USE: RawMutex = RawMutex::new();
4+
5+
// TODO: find a better place for this
6+
#[inline]
7+
fn current_cpu_cycles() -> usize {
8+
cfg_if::cfg_if! {
9+
if #[cfg(xtensa)] {
10+
xtensa_lx::timer::get_cycle_count() as usize
11+
} else if #[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2))] {
12+
riscv::register::mcycle::read()
13+
} else {
14+
const PRV_M: usize = 3;
15+
macro_rules! read_csr_fn {
16+
($fnname:ident, $csr:literal) => {
17+
#[inline]
18+
fn $fnname() -> usize {
19+
riscv::read_csr!($csr);
20+
21+
unsafe { _read() }
22+
}
23+
}
24+
}
25+
26+
read_csr_fn!(read_prv_mode, 0x810);
27+
read_csr_fn!(read_pccr_machine, 0x712);
28+
read_csr_fn!(read_pccr_user, 0x802);
29+
30+
if read_prv_mode() == PRV_M {
31+
read_pccr_machine()
32+
} else {
33+
read_pccr_user()
34+
}
35+
}
36+
}
37+
}
38+
39+
fn fill_ptr_range_inner(data: *mut u8, len: usize) {
40+
let clocks = Clocks::get();
41+
let cpu_to_apb_freq_ratio = clocks.cpu_clock / clocks.apb_clock;
42+
let wait_cycles = cpu_to_apb_freq_ratio as usize * property!("rng.apb_cycle_wait_num");
43+
44+
let mut remaining = len;
45+
let mut dst = data;
46+
let mut last_wait_start = current_cpu_cycles();
47+
while remaining > 0 {
48+
// wait
49+
loop {
50+
let now = current_cpu_cycles();
51+
if now - last_wait_start >= wait_cycles {
52+
last_wait_start = now;
53+
break;
54+
}
55+
}
56+
57+
// read
58+
let random_bytes = RNG::regs().data().read().bits().to_le_bytes();
59+
let bytes_to_copy = random_bytes.len().min(remaining);
60+
unsafe {
61+
dst.copy_from_nonoverlapping(random_bytes.as_ptr(), bytes_to_copy);
62+
dst = dst.add(bytes_to_copy);
63+
}
64+
remaining -= bytes_to_copy;
65+
}
66+
}
67+
68+
// TODO: we should also provide a non-blocking function
69+
pub(super) fn fill_ptr_range(data: *mut u8, len: usize) {
70+
RNG_IN_USE.lock(|| fill_ptr_range_inner(data, len))
71+
}

0 commit comments

Comments
 (0)