lowrisc/
csrng.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//! Support for the CSRNG hardware block on OpenTitan
6//!
7//! <https://docs.opentitan.org/hw/ip/csrng/doc>
8
9use kernel::hil::entropy::{Client32, Continue, Entropy32};
10use kernel::utilities::cells::OptionalCell;
11use kernel::utilities::registers::interfaces::{Readable, Writeable};
12use kernel::utilities::registers::{
13    register_bitfields, register_structs, ReadOnly, ReadWrite, WriteOnly,
14};
15use kernel::utilities::StaticRef;
16use kernel::ErrorCode;
17
18register_structs! {
19    pub CsRngRegisters {
20        (0x00 => intr_state: ReadWrite<u32, INTR::Register>),
21        (0x04 => intr_enable: ReadWrite<u32, INTR::Register>),
22        (0x08 => intr_test: WriteOnly<u32, INTR::Register>),
23        (0x0C => alert_test: WriteOnly<u32>),
24        (0x10 => regwen: ReadWrite<u32, REGWEN::Register>),
25        (0x14 => ctrl: ReadWrite<u32, CTRL::Register>),
26        (0x18 => cmd_req: WriteOnly<u32, COMMAND::Register>),
27        (0x1C => sw_cmd_sts: ReadOnly<u32, SW_CMD_STS::Register>),
28        (0x20 => genbits_vld: ReadOnly<u32, GENBIT_VLD::Register>),
29        (0x24 => genbits: ReadOnly<u32>),
30        (0x28 => int_state_num: ReadWrite<u32>),
31        (0x2C => int_state_val: ReadOnly<u32>),
32        (0x30 => hw_exc_sts: ReadWrite<u32>),
33        (0x34 => recov_alert_sts: ReadWrite<u32>),
34        (0x38 => err_code: ReadOnly<u32>),
35        (0x3C => err_code_test: ReadWrite<u32>),
36        (0x40 => main_sm_state: ReadOnly<u32>),
37        (0x44 => @END),
38    }
39}
40
41register_bitfields![u32,
42    INTR [
43        CMD_REQ_DONE OFFSET(0) NUMBITS(1) [],
44        ENTROPY_REQ OFFSET(1) NUMBITS(1) [],
45        HW_INST_EXC OFFSET(2) NUMBITS(1) [],
46        FATAL_ERR OFFSET(3) NUMBITS(1) [],
47    ],
48    REGWEN [
49        REGWEN OFFSET(0) NUMBITS(1) [],
50    ],
51    CTRL [
52        ENABLE OFFSET(0) NUMBITS(4) [
53            ENABLE = 0x6,
54            DISABLE = 0x9,
55        ],
56        SW_APP_ENABLE OFFSET(4) NUMBITS(4) [
57            ENABLE = 0x6,
58            DISABLE = 0x9,
59        ],
60        READ_INT_STATE OFFSET(8) NUMBITS(4) [
61            ENABLE = 0x6,
62            DISABLE = 0x9,
63        ],
64    ],
65    COMMAND [
66        ACMD OFFSET(0) NUMBITS(4) [
67            INSTANTIATE = 1,
68            RESEED = 2,
69            GENERATE = 3,
70            UPDATE = 4,
71            UNINSTANTIATE = 5,
72        ],
73        CLEN OFFSET(4) NUMBITS(4) [],
74        FLAGS OFFSET(8) NUMBITS(4) [
75            INSTANTIATE_SOURCE_XOR_SEED = 0x9,
76            INSTANTIATE_ZERO_ADDITIONAL_SEED = 0x6,
77        ],
78        GLEN OFFSET(12) NUMBITS(13) [],
79    ],
80    GENBIT_VLD [
81        GENBITS_VLD OFFSET(0) NUMBITS(1) [],
82    ],
83    SW_CMD_STS [
84        CMD_RDY OFFSET(0) NUMBITS(1) [],
85        CMD_STS OFFSET(1) NUMBITS(1) [],
86    ],
87];
88
89pub const TWO_UNITS_OF_128BIT_ENTROPY: u32 = 0x02;
90
91pub struct CsRng<'a> {
92    registers: StaticRef<CsRngRegisters>,
93
94    client: OptionalCell<&'a dyn Client32>,
95}
96
97struct CsRngIter<'a, 'b: 'a>(&'a CsRng<'b>);
98
99impl Iterator for CsRngIter<'_, '_> {
100    type Item = u32;
101
102    fn next(&mut self) -> Option<u32> {
103        if self.0.registers.genbits_vld.is_set(GENBIT_VLD::GENBITS_VLD) {
104            Some(self.0.registers.genbits.get())
105        } else {
106            None
107        }
108    }
109}
110
111impl<'a> CsRng<'a> {
112    pub const fn new(base: StaticRef<CsRngRegisters>) -> CsRng<'a> {
113        CsRng {
114            registers: base,
115            client: OptionalCell::empty(),
116        }
117    }
118
119    fn enable_interrupts(&self) {
120        self.registers.intr_enable.write(
121            INTR::CMD_REQ_DONE::SET
122                + INTR::ENTROPY_REQ::CLEAR
123                + INTR::HW_INST_EXC::SET
124                + INTR::FATAL_ERR::SET,
125        );
126    }
127
128    fn disable_interrupts(&self) {
129        self.registers.intr_state.write(
130            INTR::CMD_REQ_DONE::SET
131                + INTR::ENTROPY_REQ::SET
132                + INTR::HW_INST_EXC::SET
133                + INTR::FATAL_ERR::SET,
134        );
135
136        self.registers.intr_enable.write(
137            INTR::CMD_REQ_DONE::CLEAR
138                + INTR::ENTROPY_REQ::CLEAR
139                + INTR::HW_INST_EXC::CLEAR
140                + INTR::FATAL_ERR::CLEAR,
141        );
142    }
143
144    pub fn handle_interrupt(&self) {
145        let irqs = self.registers.intr_state.extract();
146        self.disable_interrupts();
147
148        if irqs.is_set(INTR::HW_INST_EXC) {
149            self.client.map(move |client| {
150                client.entropy_available(&mut (0..0), Err(ErrorCode::FAIL));
151            });
152            return;
153        }
154
155        if irqs.is_set(INTR::FATAL_ERR) {
156            self.client.map(move |client| {
157                client.entropy_available(&mut (0..0), Err(ErrorCode::FAIL));
158            });
159            return;
160        }
161
162        if irqs.is_set(INTR::CMD_REQ_DONE) {
163            if self
164                .client
165                .map(move |client| client.entropy_available(&mut CsRngIter(self), Ok(())))
166                == Some(Continue::More)
167            {
168                // We need more
169                if let Err(e) = self.get() {
170                    self.client.map(move |client| {
171                        client.entropy_available(&mut (0..0), Err(e));
172                    });
173                }
174            }
175        }
176    }
177
178    /// Wait for the IP to be ready for a new command, if we take too long and timeout
179    /// return BUSY. This MUST be checked prior to issuing new commands.
180    /// CMD_RDY: is set when the command interface is ready to accept a command.
181    fn wait_for_cmd_ready(&self) -> Result<(), ErrorCode> {
182        for _i in 0..10000 {
183            if self.registers.sw_cmd_sts.is_set(SW_CMD_STS::CMD_RDY) {
184                // We are ready to issue a command
185                return Ok(());
186            }
187        }
188        // Timed out
189        Err(ErrorCode::BUSY)
190    }
191}
192
193impl<'a> Entropy32<'a> for CsRng<'a> {
194    fn set_client(&'a self, client: &'a dyn Client32) {
195        self.client.set(client);
196    }
197
198    fn get(&self) -> Result<(), ErrorCode> {
199        self.disable_interrupts();
200
201        if !self.registers.regwen.is_set(REGWEN::REGWEN) {
202            // Registers are read only
203            return Err(ErrorCode::FAIL);
204        }
205
206        self.registers.ctrl.write(
207            CTRL::ENABLE::ENABLE + CTRL::READ_INT_STATE::ENABLE + CTRL::SW_APP_ENABLE::ENABLE,
208        );
209
210        // Check if IP ready for new command
211        match self.wait_for_cmd_ready() {
212            Ok(()) => {}
213            Err(e) => return Err(e),
214        }
215
216        // Init IP
217        self.registers.cmd_req.write(
218            COMMAND::ACMD::INSTANTIATE
219                + COMMAND::FLAGS::INSTANTIATE_ZERO_ADDITIONAL_SEED
220                + COMMAND::CLEN.val(0x00)
221                + COMMAND::GLEN.val(0x00),
222        );
223
224        // Check if IP ready for new command
225        match self.wait_for_cmd_ready() {
226            Ok(()) => {}
227            Err(e) => return Err(e),
228        }
229
230        self.disable_interrupts();
231        self.enable_interrupts();
232
233        // Get 256 bits of entropy
234        self.registers.cmd_req.write(
235            COMMAND::ACMD::GENERATE
236                + COMMAND::FLAGS.val(0)
237                + COMMAND::CLEN.val(0x00)
238                + COMMAND::GLEN.val(TWO_UNITS_OF_128BIT_ENTROPY),
239        );
240
241        Ok(())
242    }
243
244    fn cancel(&self) -> Result<(), ErrorCode> {
245        self.disable_interrupts();
246
247        self.registers.cmd_req.write(COMMAND::ACMD::UNINSTANTIATE);
248
249        Ok(())
250    }
251}