1use 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 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 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 return Ok(());
186 }
187 }
188 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 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 match self.wait_for_cmd_ready() {
212 Ok(()) => {}
213 Err(e) => return Err(e),
214 }
215
216 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 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 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}