Skip to content

Commit d011da9

Browse files
added testing
1 parent 475f74e commit d011da9

4 files changed

Lines changed: 172 additions & 1 deletion

File tree

boards/nucleo_u545re_q/src/main.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use kernel::component::Component;
1010
use kernel::debug::PanicResources;
1111
use kernel::deferred_call::DeferredCall;
12+
use kernel::hil::entropy::Entropy32;
1213
use kernel::platform::{KernelResources, SyscallDriverLookup};
1314
use kernel::utilities::single_thread_value::SingleThreadValue;
1415
use kernel::{capabilities, debug};
@@ -254,6 +255,20 @@ unsafe fn start() -> (
254255
stm32u545::chip::Stm32u5xx::new(periphs)
255256
);
256257

258+
// 1. Import
259+
use capsules_extra::test::rng::RngEntropy32Test;
260+
261+
// 2. Statically allocate the test struct (inside your component/board setup)
262+
let rng_test = static_init!(
263+
RngEntropy32Test<'static, stm32u545::entropy::Trng>,
264+
RngEntropy32Test::new(trng)
265+
);
266+
267+
// 3. Register the test as the driver's client
268+
trng.set_client(rng_test);
269+
270+
// 4. Kick it off — call after the kernel loop is about to start
271+
rng_test.run();
257272
// Symbols for linker
258273
extern "C" {
259274
/// Beginning of the ROM region containing app images.

capsules/extra/src/test/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub mod aes_gcm;
88
pub mod crc;
99
pub mod hmac_sha256;
1010
pub mod kv_system;
11+
pub mod rng;
1112
pub mod sha256;
1213
pub mod siphash24;
1314
pub mod udp;

capsules/extra/src/test/rng.rs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
// Licensed under the Apache License, Version 2.0 or the MIT License.
2+
// SPDX-License-Identifier: Apache-2.0 OR MIT
3+
// Copyright Tock Contributors 2024.
4+
5+
//! Integration test for an RNG driver implementing the `Entropy32` trait.
6+
//!
7+
//! This test verifies that:
8+
//! - At least 8 `u32` values can be collected from the entropy source.
9+
//! - The driver correctly handles the `Continue` / `Done` return from the
10+
//! client callback, allowing the test to "wait" (re-request) until all
11+
//! requested values have been delivered.
12+
//! - Each collected value is stored and printed for manual inspection.
13+
//!
14+
//! # Usage
15+
//!
16+
//! Add this file alongside your driver under `capsules/extra/src/` (or
17+
//! wherever your crate keeps driver tests), then register a test board that
18+
//! wires the concrete `Entropy32` implementor to `RngEntropy32Test`.
19+
//!
20+
//! ```rust,ignore
21+
//! // In your board's main.rs (or test harness):
22+
//! let rng_test = static_init!(
23+
//! capsules_extra::rng_entropy32_test::RngEntropy32Test<'static, YourRngDriver>,
24+
//! capsules_extra::rng_entropy32_test::RngEntropy32Test::new(your_rng_driver)
25+
//! );
26+
//! your_rng_driver.set_client(rng_test);
27+
//! rng_test.run();
28+
//! ```
29+
30+
use core::cell::Cell;
31+
use kernel::hil::entropy::{Client32, Entropy32};
32+
use kernel::utilities::cells::OptionalCell;
33+
use kernel::{debug, ErrorCode};
34+
35+
/// Number of `u32` words to collect before declaring the test a success.
36+
const WORDS_REQUESTED: usize = 8;
37+
38+
// ---------------------------------------------------------------------------
39+
// Test component
40+
// ---------------------------------------------------------------------------
41+
42+
pub struct RngEntropy32Test<'a, E: Entropy32<'a>> {
43+
/// Reference to the entropy source under test.
44+
rng: &'a E,
45+
/// Accumulator for collected entropy words.
46+
collected: OptionalCell<[u32; WORDS_REQUESTED]>,
47+
/// How many words we have stored so far.
48+
count: Cell<usize>,
49+
}
50+
51+
impl<'a, E: Entropy32<'a>> RngEntropy32Test<'a, E> {
52+
pub fn new(rng: &'a E) -> Self {
53+
Self {
54+
rng,
55+
collected: OptionalCell::new([0u32; WORDS_REQUESTED]),
56+
count: Cell::new(0),
57+
}
58+
}
59+
60+
/// Kick off the entropy collection. Call once after wiring the client.
61+
pub fn run(&self) {
62+
debug!(
63+
"[RNG TEST] Starting Entropy32 test — requesting {} u32 words",
64+
WORDS_REQUESTED
65+
);
66+
match self.rng.get() {
67+
Ok(()) => {}
68+
Err(e) => {
69+
debug!("[RNG TEST] FAIL: rng.get() returned error: {:?}", e);
70+
}
71+
}
72+
}
73+
74+
/// Print a summary once all words have been collected.
75+
fn finish(&self) {
76+
self.collected.map(|words| {
77+
debug!(
78+
"[RNG TEST] PASS: collected {} u32 entropy words:",
79+
WORDS_REQUESTED
80+
);
81+
for (i, w) in words.iter().enumerate() {
82+
debug!(" word[{}] = {:#010x}", i, w);
83+
}
84+
// Basic sanity: not *all* zeros (astronomically unlikely with a real RNG).
85+
let all_zero = words.iter().all(|&w| w == 0);
86+
if all_zero {
87+
debug!(
88+
"[RNG TEST] WARNING: all collected words are zero — verify your RNG source!"
89+
);
90+
}
91+
});
92+
}
93+
}
94+
95+
// ---------------------------------------------------------------------------
96+
// Entropy32 client implementation
97+
// ---------------------------------------------------------------------------
98+
99+
impl<'a, E: Entropy32<'a>> Client32 for RngEntropy32Test<'a, E> {
100+
/// Called by the driver each time a new `u32` word of entropy is ready.
101+
///
102+
/// Returns:
103+
/// - `Ok(Continue)` — ask the driver for another word (we still need more).
104+
/// - `Ok(Done)` — we have collected enough; release the hardware.
105+
fn entropy_available(
106+
&self,
107+
entropy: &mut dyn Iterator<Item = u32>,
108+
error: Result<(), ErrorCode>,
109+
) -> kernel::hil::entropy::Continue {
110+
// Surface driver-level errors but keep going — some peripheral drivers
111+
// (e.g. hardware FIFOs) report transient under-run errors yet can still
112+
// produce data; we treat them as non-fatal for test purposes.
113+
if let Err(e) = error {
114+
debug!(
115+
"[RNG TEST] entropy_available reported error: {:?} — retrying",
116+
e
117+
);
118+
return kernel::hil::entropy::Continue::More;
119+
}
120+
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+
}
142+
}
143+
done = self.count.get() >= WORDS_REQUESTED;
144+
});
145+
146+
if done {
147+
self.finish();
148+
kernel::hil::entropy::Continue::Done
149+
} else {
150+
// Not enough words yet — tell the driver to keep going / call us
151+
// again when more entropy is available.
152+
kernel::hil::entropy::Continue::More
153+
}
154+
}
155+
}

chips/stm32u5xx/src/entropy.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
use core::cell::Cell;
66

77
use kernel::deferred_call::{DeferredCall, DeferredCallClient};
8-
use kernel::hil::entropy::{self, Client32, Continue, Entropy32};
8+
use kernel::hil::entropy::{Client32, Continue, Entropy32};
99
use kernel::utilities::cells::OptionalCell;
1010
use kernel::utilities::registers::interfaces::{ReadWriteable, Readable};
1111
use kernel::utilities::registers::{register_bitfields, register_structs, ReadOnly, ReadWrite};

0 commit comments

Comments
 (0)