nrf5x/
trng.rs

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 2022.
4
5//! TRNG driver, nRF5X-family
6//!
7//! The TRNG generates 1 byte randomness at the time value in the interval
8//! 0 <= r <= 255.
9//!
10//! Because that the he capsule requires 4 bytes of randomness at the time.
11//! 4 bytes of randomness must be generated before returning  back to capsule.
12//!
13//! Therefore this module will have to use the TRNG four times.
14//! A counter `index` has been introduced to keep track of this.
15//! The four bytes of randomness is stored in a `Cell<u32>` which shifted
16//! according to append one byte at the time.
17//!
18//! In the current implementation if done > 4 for some strange reason the
19//! random generation will be restarted
20//!
21//! Authors
22//! -------------------
23//! * Niklas Adolfsson <niklasadolfsson1@gmail.com>
24//! * Fredrik Nilsson <frednils@student.chalmers.se>
25//! * Date: March 01, 2017
26
27use core::cell::Cell;
28use kernel::hil::entropy::{self, Continue};
29use kernel::utilities::cells::OptionalCell;
30use kernel::utilities::registers::interfaces::{Readable, Writeable};
31use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite, WriteOnly};
32use kernel::utilities::StaticRef;
33use kernel::ErrorCode;
34
35const RNG_BASE: StaticRef<RngRegisters> =
36    unsafe { StaticRef::new(0x4000D000 as *const RngRegisters) };
37
38#[repr(C)]
39pub struct RngRegisters {
40    /// Task starting the random number generator
41    /// Address: 0x000 - 0x004
42    pub task_start: WriteOnly<u32, Task::Register>,
43    /// Task stopping the random number generator
44    /// Address: 0x004 - 0x008
45    pub task_stop: WriteOnly<u32, Task::Register>,
46    /// Reserved
47    _reserved1: [u32; 62],
48    /// Event being generated for every new random number written to the VALUE register
49    /// Address: 0x100 - 0x104
50    pub event_valrdy: ReadWrite<u32, Event::Register>,
51    /// Reserved
52    _reserved2: [u32; 63],
53    /// Shortcut register
54    /// Address: 0x200 - 0x204
55    pub shorts: ReadWrite<u32, Shorts::Register>,
56    _reserved3: [u32; 64],
57    /// Enable interrupt
58    /// Address: 0x304 - 0x308
59    pub intenset: ReadWrite<u32, Intenset::Register>,
60    /// Disable interrupt
61    /// Address: 0x308 - 0x30c
62    pub intenclr: ReadWrite<u32, Intenclr::Register>,
63    _reserved4: [u32; 126],
64    /// Configuration register
65    /// Address: 0x504 - 0x508
66    pub config: ReadWrite<u32, Config::Register>,
67    /// Output random number
68    /// Address: 0x508 - 0x50c
69    pub value: ReadOnly<u32, Value::Register>,
70}
71
72register_bitfields! [u32,
73    /// Start task
74    Task [
75        ENABLE OFFSET(0) NUMBITS(1)
76    ],
77
78    /// Ready event
79    Event [
80        READY OFFSET(0) NUMBITS(1)
81    ],
82
83    /// Shortcut register
84    Shorts [
85        /// Shortcut between VALRDY event and STOP task
86        VALRDY_STOP OFFSET(0) NUMBITS(1)
87    ],
88
89    /// Enable interrupt
90    Intenset [
91        VALRDY OFFSET(0) NUMBITS(1)
92    ],
93
94    /// Disable interrupt
95    Intenclr [
96        VALRDY OFFSET(0) NUMBITS(1)
97    ],
98
99    /// Configuration register
100    Config [
101        /// Bias correction
102        DERCEN OFFSET(0) NUMBITS(32)
103    ],
104
105    /// Output random number
106    Value [
107        /// Generated random number
108        VALUE OFFSET(0) NUMBITS(8)
109    ]
110];
111
112pub struct Trng<'a> {
113    registers: StaticRef<RngRegisters>,
114    client: OptionalCell<&'a dyn entropy::Client32>,
115    index: Cell<usize>,
116    randomness: Cell<u32>,
117}
118
119impl<'a> Trng<'a> {
120    pub const fn new() -> Trng<'a> {
121        Trng {
122            registers: RNG_BASE,
123            client: OptionalCell::empty(),
124            index: Cell::new(0),
125            randomness: Cell::new(0),
126        }
127    }
128
129    /// RNG Interrupt handler
130    pub fn handle_interrupt(&self) {
131        self.disable_interrupts();
132
133        match self.index.get() {
134            // fetch more data need 4 bytes because the capsule requires that
135            e @ 0..=3 => {
136                // 3 lines below to change data in Cell, perhaps it can be done more nicely
137                let mut rn = self.randomness.get();
138                // 1 byte randomness
139                let r = self.registers.value.get();
140                //  e = 0 -> byte 1 LSB
141                //  e = 1 -> byte 2
142                //  e = 2 -> byte 3
143                //  e = 3 -> byte 4 MSB
144                rn |= r << (8 * e);
145                self.randomness.set(rn);
146
147                self.index.set(e + 1);
148                self.start_rng()
149            }
150            // fetched 4 bytes of data generated, then notify the capsule
151            4 => {
152                self.client.map(|client| {
153                    let result = client.entropy_available(&mut TrngIter(self), Ok(()));
154                    if Continue::Done != result {
155                        // need more randomness i.e generate more randomness
156                        self.start_rng();
157                    }
158                });
159            }
160            // This should never happen if the logic is correct
161            // Restart randomness generation if this condition occurs
162            _ => {
163                self.index.set(0);
164                self.randomness.set(0);
165            }
166        }
167    }
168
169    fn enable_interrupts(&self) {
170        self.registers.intenset.write(Intenset::VALRDY::SET);
171    }
172
173    fn disable_interrupts(&self) {
174        self.registers.intenclr.write(Intenclr::VALRDY::SET);
175    }
176
177    fn start_rng(&self) {
178        // Reset `valrdy`
179        self.registers.event_valrdy.write(Event::READY::CLEAR);
180
181        // Enable interrupts
182        self.enable_interrupts();
183
184        // Start rng
185        self.registers.task_start.write(Task::ENABLE::SET);
186    }
187}
188
189struct TrngIter<'a, 'b: 'a>(&'a Trng<'b>);
190
191impl Iterator for TrngIter<'_, '_> {
192    type Item = u32;
193
194    fn next(&mut self) -> Option<u32> {
195        if self.0.index.get() == 4 {
196            let rn = self.0.randomness.get();
197            // indicate 4 bytes of randomness taken by the capsule
198            self.0.index.set(0);
199            self.0.randomness.set(0);
200            Some(rn)
201        } else {
202            None
203        }
204    }
205}
206
207impl<'a> entropy::Entropy32<'a> for Trng<'a> {
208    fn get(&self) -> Result<(), ErrorCode> {
209        self.start_rng();
210        Ok(())
211    }
212
213    fn cancel(&self) -> Result<(), ErrorCode> {
214        Err(ErrorCode::FAIL)
215    }
216
217    fn set_client(&'a self, client: &'a dyn entropy::Client32) {
218        self.client.set(client);
219    }
220}