Skip to content

Commit 475f74e

Browse files
Added support for rng generator, first draft
1 parent 06dcd56 commit 475f74e

6 files changed

Lines changed: 217 additions & 7 deletions

File tree

boards/nucleo_u545re_q/src/main.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
#![no_std]
77
#![no_main]
88

9-
use kernel::capabilities;
109
use kernel::component::Component;
1110
use kernel::debug::PanicResources;
11+
use kernel::deferred_call::DeferredCall;
1212
use kernel::platform::{KernelResources, SyscallDriverLookup};
1313
use kernel::utilities::single_thread_value::SingleThreadValue;
14+
use kernel::{capabilities, debug};
1415
use kernel::{create_capability, static_init};
1516

1617
use stm32u545::gpio::PinId;
@@ -148,11 +149,15 @@ unsafe fn start() -> (
148149
stm32u545::usart::Usart<'static>,
149150
stm32u545::usart::Usart::new(stm32u545::usart::USART1_BASE)
150151
);
152+
let trng = static_init!(
153+
stm32u545::entropy::Trng<'static>,
154+
stm32u545::entropy::Trng::new(stm32u545::entropy::RNG_BASE, DeferredCall::new())
155+
);
151156

152157
// Load Peripherals Bundle
153158
let periphs = static_init!(
154159
stm32u545::chip::Stm32u5xxDefaultPeripherals<'static>,
155-
stm32u545::chip::Stm32u5xxDefaultPeripherals::new(usart1, exti, dma1)
160+
stm32u545::chip::Stm32u5xxDefaultPeripherals::new(usart1, exti, dma1, trng)
156161
);
157162

158163
// Initialize wiring (DMA, clocks)

chips/stm32u545/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
#![no_std]
66

7-
pub use stm32u5xx::{chip, dma, exti, gpio, rcc, tim, usart};
7+
pub use stm32u5xx::{chip, dma, entropy, exti, gpio, rcc, tim, usart};
88

99
use cortexm33::{CortexM33, CortexMVariant};
1010

chips/stm32u5xx/src/chip.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@
44
// Copyright OxidOS Automotive 2026.
55

66
use crate::dma::{ChannelId, Dma};
7-
use crate::exti;
7+
use crate::entropy::Trng;
88
use crate::gpio;
99
use crate::nvic::{
1010
EXTI13_IRQ, GPDMA1_CH0_IRQ, GPDMA1_CH10_IRQ, GPDMA1_CH11_IRQ, GPDMA1_CH12_IRQ, GPDMA1_CH13_IRQ,
1111
GPDMA1_CH14_IRQ, GPDMA1_CH15_IRQ, GPDMA1_CH1_IRQ, GPDMA1_CH2_IRQ, GPDMA1_CH3_IRQ,
1212
GPDMA1_CH4_IRQ, GPDMA1_CH5_IRQ, GPDMA1_CH6_IRQ, GPDMA1_CH7_IRQ, GPDMA1_CH8_IRQ, GPDMA1_CH9_IRQ,
13-
TIM2_IRQ, USART1_IRQ,
13+
RNG_IRQ, TIM2_IRQ, USART1_IRQ,
1414
};
1515
use crate::rcc;
1616
use crate::tim;
1717
use crate::usart;
18+
use crate::{entropy, exti};
1819

1920
use core::fmt::Write;
2021
use kernel::platform::chip::Chip;
@@ -34,6 +35,7 @@ pub struct Stm32u5xxDefaultPeripherals<'a> {
3435
pub dma1: &'a Dma,
3536
pub gpio_a: gpio::Port<'a>,
3637
pub gpio_c: gpio::Port<'a>,
38+
pub trng: &'a entropy::Trng<'a>,
3739
}
3840

3941
fn enable_tim2_clock() {
@@ -42,7 +44,12 @@ fn enable_tim2_clock() {
4244
}
4345

4446
impl<'a> Stm32u5xxDefaultPeripherals<'a> {
45-
pub fn new(usart1: &'a usart::Usart<'a>, exti: &'a exti::Exti<'a>, dma1: &'a Dma) -> Self {
47+
pub fn new(
48+
usart1: &'a usart::Usart<'a>,
49+
exti: &'a exti::Exti<'a>,
50+
dma1: &'a Dma,
51+
trng: &'a Trng<'a>,
52+
) -> Self {
4653
Self {
4754
rcc: rcc::Rcc::new(rcc::RCC_BASE),
4855
tim2: tim::Tim2::new(tim::TIM2_BASE, enable_tim2_clock),
@@ -51,6 +58,7 @@ impl<'a> Stm32u5xxDefaultPeripherals<'a> {
5158
dma1,
5259
gpio_a: gpio::Port::new(gpio::GPIO_A_BASE, exti, gpio::GpioPort::PortA),
5360
gpio_c: gpio::Port::new(gpio::GPIO_C_BASE, exti, gpio::GpioPort::PortC),
61+
trng,
5462
}
5563
}
5664

@@ -61,6 +69,8 @@ impl<'a> Stm32u5xxDefaultPeripherals<'a> {
6169
self.rcc.enable_gpioc();
6270
self.rcc.enable_usart1();
6371
self.rcc.enable_syscfg();
72+
self.rcc.enable_trng();
73+
self.trng.init();
6474
self.rcc.set_usart1_source_pclk();
6575
// Link DMA to USART1
6676
let usart1_channel_tx = self.dma1.request_channel();
@@ -155,6 +165,10 @@ impl InterruptService for Stm32u5xxDefaultPeripherals<'_> {
155165
self.dma1.handle_interrupt(ChannelId::Channel15);
156166
true
157167
}
168+
RNG_IRQ => {
169+
self.trng.handle_interrupt();
170+
true
171+
}
158172
_ => false,
159173
}
160174
}

chips/stm32u5xx/src/entropy.rs

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
// Licensed under the Apache License, Version 2.0 or the MIT License.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
// Copyright OxidOS Automotive 2026.
4+
5+
use core::cell::Cell;
6+
7+
use kernel::deferred_call::{DeferredCall, DeferredCallClient};
8+
use kernel::hil::entropy::{self, Client32, Continue, Entropy32};
9+
use kernel::utilities::cells::OptionalCell;
10+
use kernel::utilities::registers::interfaces::{ReadWriteable, Readable};
11+
use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};
12+
use kernel::utilities::StaticRef;
13+
14+
register_structs! {
15+
/// Random number generator
16+
pub RngRegisters {
17+
/// control register
18+
(0x000 => cr: ReadWrite<u32, CR::Register>),
19+
/// status register
20+
(0x004 => sr: ReadWrite<u32, SR::Register>),
21+
/// data register
22+
(0x008 => dr: ReadOnly<u32>),
23+
(0x00C => nscr: ReadWrite<u32, NSCR::Register>),
24+
/// health test control register
25+
(0x010 => htcr: ReadWrite<u32, HTCR::Register>),
26+
(0x014 => @END),
27+
}
28+
}
29+
register_bitfields![u32,
30+
pub CR [
31+
/// RNG Config Lock
32+
CONFIGLOCK OFFSET(31) NUMBITS(1) [],
33+
/// Conditioning soft reset
34+
CONDRST OFFSET(30) NUMBITS(1) [],
35+
/// RNG configuration 1
36+
RNG_CONFIG1 OFFSET(20) NUMBITS(6) [],
37+
/// Clock divider factor
38+
CLKDIV OFFSET(16) NUMBITS(4) [],
39+
/// RNG configuration 2
40+
RNG_CONFIG2 OFFSET(13) NUMBITS(3) [],
41+
/// Non NIST compliant
42+
NISTC OFFSET(12) NUMBITS(1) [],
43+
/// RNG configuration 3
44+
RNG_CONFIG3 OFFSET(8) NUMBITS(4) [],
45+
/// Auto reset disable
46+
ARDIS OFFSET(7) NUMBITS(1) [],
47+
/// Clock error detection
48+
CED OFFSET(5) NUMBITS(1) [],
49+
/// Interrupt Enable
50+
IE OFFSET(3) NUMBITS(1) [],
51+
/// True random number generator enable
52+
RNGEN OFFSET(2) NUMBITS(1) []
53+
],
54+
pub SR [
55+
/// Seed error interrupt status
56+
SEIS OFFSET(6) NUMBITS(1) [],
57+
/// Clock error interrupt status
58+
CEIS OFFSET(5) NUMBITS(1) [],
59+
/// Seed error current status
60+
SECS OFFSET(2) NUMBITS(1) [],
61+
/// Clock error current status
62+
CECS OFFSET(1) NUMBITS(1) [],
63+
/// Data ready
64+
DRDY OFFSET(0) NUMBITS(1) []
65+
],
66+
pub DR [
67+
/// Random data
68+
RNDATA OFFSET(0) NUMBITS(32) []
69+
],
70+
pub NSCR [
71+
/// noise source control register
72+
NSCFG OFFSET(0) NUMBITS(32) []
73+
],
74+
pub HTCR [
75+
/// health test configuration
76+
HTCFG OFFSET(0) NUMBITS(32) []
77+
]
78+
];
79+
pub const RNG_BASE: StaticRef<RngRegisters> =
80+
unsafe { StaticRef::new(0x520C0800 as *const RngRegisters) };
81+
82+
struct TrngIter<'a, 'b: 'a>(&'a Trng<'b>);
83+
impl Iterator for TrngIter<'_, '_> {
84+
type Item = u32;
85+
86+
fn next(&mut self) -> Option<u32> {
87+
if self.0.registers.sr.is_set(SR::DRDY) {
88+
Some(self.0.registers.dr.get())
89+
} else {
90+
None
91+
}
92+
}
93+
}
94+
95+
pub struct Trng<'a> {
96+
registers: StaticRef<RngRegisters>,
97+
client: OptionalCell<&'a dyn Client32>,
98+
entropy_needed: Cell<bool>,
99+
deferred_call: DeferredCall,
100+
}
101+
102+
impl<'a> Trng<'a> {
103+
pub const fn new(base: StaticRef<RngRegisters>, deferred_call: DeferredCall) -> Self {
104+
Self {
105+
registers: base,
106+
client: OptionalCell::empty(),
107+
entropy_needed: Cell::new(false),
108+
deferred_call: deferred_call,
109+
}
110+
}
111+
112+
pub fn init(&self) {
113+
// specified in the documentation (NIST compliant RNG configuration table in AN4230 available from www.st.com.)
114+
// that values for the CR, HTCR and NSCR should be 0x00F11F00, 0x76B3 and 0x24C2 respectivly
115+
self.registers.cr.modify(
116+
CR::RNG_CONFIG3.val(0b1111)
117+
+ CR::NISTC::SET
118+
+ CR::CLKDIV.val(0x1)
119+
+ CR::RNG_CONFIG1.val(0b1111)
120+
+ CR::CONDRST::SET,
121+
);
122+
self.registers.htcr.modify(HTCR::HTCFG.val(0x76B3));
123+
self.registers.nscr.modify(NSCR::NSCFG.val(0x24C2));
124+
self.registers.cr.modify(CR::CONFIGLOCK::SET);
125+
self.registers
126+
.cr
127+
.modify(CR::RNGEN::SET + CR::IE::SET + CR::CONDRST::CLEAR);
128+
}
129+
fn send_data(&self) {
130+
let response = self
131+
.client
132+
.map(|client| client.entropy_available(&mut TrngIter(self), Ok(())));
133+
match response {
134+
Some(Continue::Done) | None => self.entropy_needed.set(false),
135+
_ => {}
136+
}
137+
}
138+
139+
pub fn handle_interrupt(&self) {
140+
let regs = self.registers;
141+
if regs.sr.any_matching_bits_set(SR::DRDY::SET) && self.entropy_needed.get() {
142+
self.send_data();
143+
}
144+
}
145+
}
146+
147+
impl<'a> Entropy32<'a> for Trng<'a> {
148+
fn get(&self) -> Result<(), kernel::ErrorCode> {
149+
let regs = self.registers;
150+
if regs.sr.any_matching_bits_set(SR::CECS::SET + SR::SECS::SET) {
151+
return Err(kernel::ErrorCode::FAIL);
152+
}
153+
self.entropy_needed.set(true);
154+
self.deferred_call.set();
155+
156+
Ok(())
157+
}
158+
159+
fn cancel(&self) -> Result<(), kernel::ErrorCode> {
160+
if self.entropy_needed.get() {
161+
self.entropy_needed.set(false);
162+
}
163+
Ok(())
164+
}
165+
166+
fn set_client(&'a self, client: &'a dyn kernel::hil::entropy::Client32) {
167+
self.client.set(client);
168+
}
169+
}
170+
171+
impl DeferredCallClient for Trng<'_> {
172+
fn handle_deferred_call(&self) {
173+
if !self.entropy_needed.get() {
174+
return;
175+
}
176+
177+
if self.registers.sr.any_matching_bits_set(SR::DRDY::SET) {
178+
self.send_data();
179+
}
180+
}
181+
182+
fn register(&'static self) {
183+
self.deferred_call.register(self);
184+
}
185+
}

chips/stm32u5xx/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
pub mod chip;
88
pub mod dma;
9+
pub mod entropy;
910
pub mod exti;
1011
pub mod gpio;
1112
pub mod nvic;

chips/stm32u5xx/src/rcc.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ register_bitfields![u32,
4545
GPIOGEN OFFSET(6) NUMBITS(1) [],
4646
GPIOHEN OFFSET(7) NUMBITS(1) [],
4747
GPIOIEN OFFSET(8) NUMBITS(1) [],
48-
GPIOJEN OFFSET(9) NUMBITS(1) []
48+
GPIOJEN OFFSET(9) NUMBITS(1) [],
49+
TRNGEN OFFSET(18) NUMBITS(1) []
4950
],
5051
pub APB1ENR1 [
5152
TIM2EN OFFSET(0) NUMBITS(1) []
@@ -103,6 +104,10 @@ impl Rcc {
103104
self.registers.apb3enr.modify(APB3ENR::SYSCFGEN::SET);
104105
}
105106

107+
pub fn enable_trng(&self) {
108+
self.registers.ahb2enr1.modify(AHB2ENR1::TRNGEN::SET);
109+
}
110+
106111
pub fn set_usart1_source_pclk(&self) {
107112
self.registers.ccipr1.modify(CCIPR1::USART1SEL::PCLK);
108113
}

0 commit comments

Comments
 (0)