capsules_core/virtualizers/
virtual_rng.rs
1use core::cell::Cell;
7use kernel::collections::list::{List, ListLink, ListNode};
8use kernel::hil::rng::{Client, Continue, Rng};
9use kernel::utilities::cells::OptionalCell;
10use kernel::ErrorCode;
11
12#[derive(Copy, Clone, PartialEq)]
13enum Op {
14 Idle,
15 Get,
16}
17
18pub struct MuxRngMaster<'a> {
20 rng: &'a dyn Rng<'a>,
21 devices: List<'a, VirtualRngMasterDevice<'a>>,
22 inflight: OptionalCell<&'a VirtualRngMasterDevice<'a>>,
23}
24
25impl<'a> MuxRngMaster<'a> {
26 pub const fn new(rng: &'a dyn Rng<'a>) -> MuxRngMaster<'a> {
27 MuxRngMaster {
28 rng,
29 devices: List::new(),
30 inflight: OptionalCell::empty(),
31 }
32 }
33
34 fn do_next_op(&self) -> Result<(), ErrorCode> {
35 if self.inflight.is_none() {
36 let mnode = self
37 .devices
38 .iter()
39 .find(|node| node.operation.get() != Op::Idle);
40
41 let return_code = mnode.map(|node| {
42 let op = node.operation.get();
43 let operation_code = match op {
44 Op::Get => {
45 let success_code = self.rng.get();
46
47 if success_code == Ok(()) {
49 self.inflight.set(node);
50 }
51 success_code
52 }
53 Op::Idle => unreachable!("Attempted to run idle operation in virtual_rng!"), };
55
56 node.operation.set(Op::Idle);
58 operation_code
59 });
60
61 if let Some(r) = return_code {
63 r
64 } else {
65 Err(ErrorCode::FAIL)
66 }
67 } else {
68 Ok(())
69 }
70 }
71}
72
73impl Client for MuxRngMaster<'_> {
74 fn randomness_available(
75 &self,
76 _randomness: &mut dyn Iterator<Item = u32>,
77 _error: Result<(), ErrorCode>,
78 ) -> Continue {
79 self.inflight.take().map_or(Continue::Done, |device| {
81 let cont_code = device.randomness_available(_randomness, _error);
82
83 if cont_code == Continue::Done {
84 let _ = self.do_next_op();
85 }
86
87 cont_code
88 })
89 }
90}
91
92pub struct VirtualRngMasterDevice<'a> {
94 mux: &'a MuxRngMaster<'a>,
96
97 next: ListLink<'a, VirtualRngMasterDevice<'a>>,
99 client: OptionalCell<&'a dyn Client>,
100 operation: Cell<Op>,
101}
102
103impl<'a> ListNode<'a, VirtualRngMasterDevice<'a>> for VirtualRngMasterDevice<'a> {
105 fn next(&self) -> &'a ListLink<VirtualRngMasterDevice<'a>> {
106 &self.next
107 }
108}
109
110impl<'a> VirtualRngMasterDevice<'a> {
111 pub const fn new(mux: &'a MuxRngMaster<'a>) -> VirtualRngMasterDevice<'a> {
112 VirtualRngMasterDevice {
113 mux,
114 next: ListLink::empty(),
115 client: OptionalCell::empty(),
116 operation: Cell::new(Op::Idle),
117 }
118 }
119}
120
121impl<'a> PartialEq<VirtualRngMasterDevice<'a>> for VirtualRngMasterDevice<'a> {
122 fn eq(&self, other: &VirtualRngMasterDevice<'a>) -> bool {
123 core::ptr::eq(self, other)
125 }
126}
127
128impl<'a> Rng<'a> for VirtualRngMasterDevice<'a> {
129 fn get(&self) -> Result<(), ErrorCode> {
130 self.operation.set(Op::Get);
131 self.mux.do_next_op()
132 }
133
134 fn cancel(&self) -> Result<(), ErrorCode> {
135 self.operation.set(Op::Idle);
137
138 self.mux.inflight.map_or_else(
139 || {
140 Ok(())
142 },
143 |current_node| {
144 if current_node == self {
146 self.mux.rng.cancel()
147 } else {
148 Ok(())
149 }
150 },
151 )
152 }
153
154 fn set_client(&'a self, client: &'a dyn Client) {
155 self.mux.devices.push_head(self);
156
157 self.client.set(client);
159
160 self.mux.rng.set_client(self.mux);
162 }
163}
164
165impl Client for VirtualRngMasterDevice<'_> {
166 fn randomness_available(
167 &self,
168 randomness: &mut dyn Iterator<Item = u32>,
169 error: Result<(), ErrorCode>,
170 ) -> Continue {
171 self.client.map_or(Continue::Done, move |client| {
172 client.randomness_available(randomness, error)
173 })
174 }
175}