Skip to content

Commit f65bc30

Browse files
finished TRNG implementation in low power mode
1 parent 78e3d11 commit f65bc30

4 files changed

Lines changed: 91 additions & 65 deletions

File tree

boards/nucleo_u545re_q/src/main.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ use kernel::debug::PanicResources;
1111
use kernel::deferred_call::{DeferredCall, DeferredCallClient};
1212
use kernel::hil::entropy::Entropy32;
1313
use kernel::platform::{KernelResources, SyscallDriverLookup};
14-
use kernel::utilities::registers::interfaces::Readable;
15-
use kernel::utilities::registers::interfaces::Writeable;
1614
use kernel::utilities::single_thread_value::SingleThreadValue;
1715
use kernel::{capabilities, debug};
1816
use kernel::{create_capability, static_init};
@@ -154,7 +152,7 @@ unsafe fn start() -> (
154152
);
155153
let trng = static_init!(
156154
stm32u545::entropy::Trng<'static>,
157-
stm32u545::entropy::Trng::new(stm32u545::entropy::RNG_BASE, DeferredCall::new())
155+
stm32u545::entropy::Trng::new(stm32u545::entropy::RNG_BASE)
158156
);
159157

160158
// Load Peripherals Bundle
@@ -298,8 +296,8 @@ unsafe fn start() -> (
298296
);
299297

300298
// 3. Register the test as the driver's client
299+
rng_test.register();
301300
trng.set_client(rng_test);
302-
trng.register();
303301
// 4. Kick it off — call after the kernel loop is about to start
304302
// // temporary diagnostic
305303
rng_test.run();

capsules/extra/src/test/rng.rs

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@
2828
//! ```
2929
3030
use core::cell::Cell;
31+
use kernel::deferred_call::{DeferredCall, DeferredCallClient};
3132
use kernel::hil::entropy::{Client32, Entropy32};
3233
use kernel::utilities::cells::OptionalCell;
3334
use kernel::{debug, ErrorCode};
3435

3536
/// Number of `u32` words to collect before declaring the test a success.
36-
const WORDS_REQUESTED: usize = 8;
37+
const WORDS_REQUESTED: usize = 5;
38+
const NUM_ROUNDS: usize = 2;
3739

3840
// ---------------------------------------------------------------------------
3941
// Test component
@@ -46,6 +48,8 @@ pub struct RngEntropy32Test<'a, E: Entropy32<'a>> {
4648
collected: OptionalCell<[u32; WORDS_REQUESTED]>,
4749
/// How many words we have stored so far.
4850
count: Cell<usize>,
51+
round: Cell<usize>,
52+
def: DeferredCall,
4953
}
5054

5155
impl<'a, E: Entropy32<'a>> RngEntropy32Test<'a, E> {
@@ -54,6 +58,8 @@ impl<'a, E: Entropy32<'a>> RngEntropy32Test<'a, E> {
5458
rng,
5559
collected: OptionalCell::new([0u32; WORDS_REQUESTED]),
5660
count: Cell::new(0),
61+
round: Cell::new(0),
62+
def: DeferredCall::new(),
5763
}
5864
}
5965

@@ -81,8 +87,10 @@ impl<'a, E: Entropy32<'a>> RngEntropy32Test<'a, E> {
8187
for (i, w) in words.iter().enumerate() {
8288
debug!(" word[{}] = {:#010x}", i, w);
8389
}
84-
// Basic sanity: not *all* zeros (astronomically unlikely with a real RNG).
85-
let all_zero = words.iter().all(|&w| w == 0);
90+
if self.round.get() < NUM_ROUNDS {
91+
self.def.set();
92+
}
93+
let all_zero = words.iter().any(|&w| w == 0);
8694
if all_zero {
8795
debug!(
8896
"[RNG TEST] WARNING: all collected words are zero — verify your RNG source!"
@@ -118,31 +126,21 @@ impl<'a, E: Entropy32<'a>> Client32 for RngEntropy32Test<'a, E> {
118126
return kernel::hil::entropy::Continue::More;
119127
}
120128

121-
let mut done = false;
122-
123-
self.collected.map(|mut words: [u32; 8]| {
124-
// Drain as many words as the iterator offers in this callback.
125-
for word in &mut *entropy {
126-
let idx = self.count.get();
127-
if idx >= WORDS_REQUESTED {
128-
break;
129-
}
130-
words[idx] = word;
131-
self.count.set(idx + 1);
132-
debug!(
133-
"[RNG TEST] word[{}] = {:#010x} ({}/{} collected)",
134-
idx,
135-
word,
136-
idx + 1,
137-
WORDS_REQUESTED
138-
);
139-
if idx + 1 >= WORDS_REQUESTED {
140-
break;
141-
}
129+
let mut words = self.collected.take().unwrap_or([0u32; WORDS_REQUESTED]);
130+
// Drain as many words as the iterator offers in this callback.
131+
for word in entropy {
132+
let idx = self.count.get();
133+
if idx >= WORDS_REQUESTED {
134+
break;
142135
}
143-
done = self.count.get() >= WORDS_REQUESTED;
144-
});
145-
136+
words[idx] = word;
137+
self.count.set(idx + 1);
138+
if idx + 1 >= WORDS_REQUESTED {
139+
break;
140+
}
141+
}
142+
let done = self.count.get() >= WORDS_REQUESTED;
143+
self.collected.set(words);
146144
if done {
147145
self.finish();
148146
kernel::hil::entropy::Continue::Done
@@ -153,3 +151,16 @@ impl<'a, E: Entropy32<'a>> Client32 for RngEntropy32Test<'a, E> {
153151
}
154152
}
155153
}
154+
155+
impl<'a, E: Entropy32<'a>> DeferredCallClient for RngEntropy32Test<'a, E> {
156+
fn handle_deferred_call(&self) {
157+
let round = self.round.get();
158+
self.round.set(round + 1);
159+
self.count.set(0);
160+
self.run();
161+
}
162+
163+
fn register(&'static self) {
164+
self.def.register(self);
165+
}
166+
}

chips/stm32u5xx/src/chip.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ impl<'a> Stm32u5xxDefaultPeripherals<'a> {
7171
self.rcc.enable_usart1();
7272
self.rcc.enable_syscfg();
7373
self.rcc.enable_trng();
74-
self.trng.register();
7574
self.rcc.set_usart1_source_pclk();
7675
// Link DMA to USART1
7776
let usart1_channel_tx = self.dma1.request_channel();
@@ -80,6 +79,7 @@ impl<'a> Stm32u5xxDefaultPeripherals<'a> {
8079
if let (Some(tx), Some(rx)) = (usart1_channel_tx, usart1_channel_rx) {
8180
usart::Usart::set_dma(self.usart1, self.dma1, tx, rx);
8281
}
82+
self.trng.init();
8383
}
8484
}
8585

@@ -166,10 +166,6 @@ impl InterruptService for Stm32u5xxDefaultPeripherals<'_> {
166166
self.dma1.handle_interrupt(ChannelId::Channel15);
167167
true
168168
}
169-
RNG_IRQ => {
170-
self.trng.handle_interrupt();
171-
true
172-
}
173169
_ => false,
174170
}
175171
}

chips/stm32u5xx/src/entropy.rs

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
// Copyright OxidOS Automotive 2026.
44

55
use core::cell::Cell;
6-
use kernel::debug;
76

87
use kernel::deferred_call::{DeferredCall, DeferredCallClient};
98
use kernel::hil::entropy::{Client32, Continue, Entropy32};
@@ -12,6 +11,9 @@ use kernel::utilities::registers::interfaces::{ReadWriteable, Readable};
1211
use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
1312
use kernel::utilities::StaticRef;
1413

14+
const HEALTH_TEST_CONTROL_CONFIG: u32 = 0x76B3;
15+
const NOISE_SOURCE_CONTROL_CONFIG: u32 = 0x24C2;
16+
1517
register_structs! {
1618
/// Random number generator
1719
pub RngRegisters {
@@ -93,6 +95,15 @@ impl Iterator for TrngIter<'_, '_> {
9395
}
9496
}
9597

98+
struct ErrIter;
99+
impl Iterator for ErrIter {
100+
type Item = u32;
101+
102+
fn next(&mut self) -> Option<Self::Item> {
103+
None
104+
}
105+
}
106+
96107
pub struct Trng<'a> {
97108
registers: StaticRef<RngRegisters>,
98109
client: OptionalCell<&'a dyn Client32>,
@@ -101,16 +112,16 @@ pub struct Trng<'a> {
101112
}
102113

103114
impl<'a> Trng<'a> {
104-
pub const fn new(base: StaticRef<RngRegisters>, deferred_call: DeferredCall) -> Self {
115+
pub fn new(base: StaticRef<RngRegisters>) -> Self {
105116
Self {
106117
registers: base,
107118
client: OptionalCell::empty(),
108119
entropy_needed: Cell::new(false),
109-
deferred_call: deferred_call,
120+
deferred_call: DeferredCall::new(),
110121
}
111122
}
112123

113-
pub fn init(&self) {
124+
pub fn init(&'static self) {
114125
// specified in the documentation (NIST compliant RNG configuration table in AN4230 available from www.st.com.)
115126
// that values for the CR, HTCR and NSCR should be 0x00F11F00, 0x76B3 and 0x24C2 respectivly
116127
self.registers.cr.modify(
@@ -120,45 +131,43 @@ impl<'a> Trng<'a> {
120131
+ CR::RNG_CONFIG1.val(0b1111)
121132
+ CR::CONDRST::SET,
122133
);
123-
self.registers.htcr.modify(HTCR::HTCFG.val(0x76B3));
124-
self.registers.nscr.modify(NSCR::NSCFG.val(0x24C2));
125-
self.registers.cr.modify(CR::CONFIGLOCK::SET);
126134
self.registers
127-
.cr
128-
.modify(CR::RNGEN::SET + CR::IE::SET + CR::CONDRST::CLEAR);
129-
debug!("CR: {:02x?}", self.registers.cr.get());
135+
.htcr
136+
.modify(HTCR::HTCFG.val(HEALTH_TEST_CONTROL_CONFIG));
137+
self.registers
138+
.nscr
139+
.modify(NSCR::NSCFG.val(NOISE_SOURCE_CONTROL_CONFIG));
140+
self.registers.cr.modify(CR::CONFIGLOCK::SET);
141+
self.registers.cr.modify(CR::CONDRST::CLEAR);
142+
self.register();
130143
}
144+
131145
fn send_data(&self) {
146+
self.entropy_needed.set(false);
132147
let response = self
133148
.client
134149
.map(|client| client.entropy_available(&mut TrngIter(self), Ok(())));
135150
match response {
136-
Some(Continue::Done) | None => self.entropy_needed.set(false),
151+
Some(Continue::Done) | None => {
152+
self.registers.cr.modify(CR::RNGEN::CLEAR);
153+
}
137154
_ => {
155+
self.entropy_needed.set(true);
138156
self.deferred_call.set();
139157
}
140158
}
141159
}
142-
143-
pub fn handle_interrupt(&self) {
144-
let regs = self.registers;
145-
if regs.sr.any_matching_bits_set(SR::DRDY::SET) && self.entropy_needed.get() {
146-
self.send_data();
147-
} else {
148-
self.deferred_call.set();
149-
}
150-
}
151160
}
152161

153162
impl<'a> Entropy32<'a> for Trng<'a> {
154163
fn get(&self) -> Result<(), kernel::ErrorCode> {
155164
let regs = self.registers;
165+
regs.cr.modify(CR::RNGEN::SET);
156166
if regs.sr.any_matching_bits_set(SR::CECS::SET + SR::SECS::SET) {
157167
return Err(kernel::ErrorCode::FAIL);
158168
}
159169
self.entropy_needed.set(true);
160170
self.deferred_call.set();
161-
162171
Ok(())
163172
}
164173

@@ -176,19 +185,31 @@ impl<'a> Entropy32<'a> for Trng<'a> {
176185

177186
impl DeferredCallClient for Trng<'_> {
178187
fn handle_deferred_call(&self) {
179-
debug!("got");
188+
if self.registers.sr.is_set(SR::SECS) {
189+
self.registers.sr.modify(SR::SEIS::CLEAR);
190+
if self.entropy_needed.get() {
191+
self.client.map(|client| {
192+
client.entropy_available(&mut ErrIter, Err(kernel::ErrorCode::FAIL))
193+
});
194+
}
195+
return;
196+
}
197+
if self.registers.sr.is_set(SR::CECS) {
198+
self.registers.sr.modify(SR::CEIS::CLEAR);
199+
if self.entropy_needed.get() {
200+
self.client.map(|client| {
201+
client.entropy_available(&mut ErrIter, Err(kernel::ErrorCode::FAIL))
202+
});
203+
}
204+
return;
205+
}
180206
if !self.entropy_needed.get() {
181207
return;
182208
}
183-
debug!(
184-
"CR: {:02x?} SR: {:02x?}, need: {}",
185-
self.registers.cr.get(),
186-
self.registers.sr.get(),
187-
self.entropy_needed.get()
188-
);
189-
190209
if self.registers.sr.any_matching_bits_set(SR::DRDY::SET) {
191210
self.send_data();
211+
} else {
212+
self.deferred_call.set();
192213
}
193214
}
194215

0 commit comments

Comments
 (0)