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.
45use core::cell::Cell;
67use kernel::deferred_call::{DeferredCall, DeferredCallClient};
8use kernel::hil::rng::{Client as RngClient, Continue as RngCont, Rng};
9use kernel::utilities::cells::OptionalCell;
10use kernel::ErrorCode;
1112use super::super::devices::{VirtIODeviceDriver, VirtIODeviceType};
13use super::super::queues::split_queue::{SplitVirtqueue, SplitVirtqueueClient, VirtqueueBuffer};
1415pub struct VirtIORng<'a, 'b> {
16 virtqueue: &'a SplitVirtqueue<'a, 'b, 1>,
17 buffer_capacity: Cell<usize>,
18 callback_pending: Cell<bool>,
19 deferred_call: DeferredCall,
20 client: OptionalCell<&'a dyn RngClient>,
21}
2223impl<'a, 'b> VirtIORng<'a, 'b> {
24pub fn new(virtqueue: &'a SplitVirtqueue<'a, 'b, 1>) -> VirtIORng<'a, 'b> {
25 VirtIORng {
26 virtqueue,
27 buffer_capacity: Cell::new(0),
28 callback_pending: Cell::new(false),
29 deferred_call: DeferredCall::new(),
30 client: OptionalCell::empty(),
31 }
32 }
3334pub fn provide_buffer(&self, buf: &'b mut [u8]) -> Result<usize, (&'b mut [u8], ErrorCode)> {
35let len = buf.len();
36if len < 4 {
37// We don't yet support merging of randomness of multiple buffers
38 //
39 // Allowing a buffer with less than 4 elements will cause
40 // the callback to never be called, while the buffer is
41 // reinserted into the queue
42return Err((buf, ErrorCode::INVAL));
43 }
4445let mut buffer_chain = [Some(VirtqueueBuffer {
46 buf,
47 len,
48 device_writeable: true,
49 })];
5051let res = self.virtqueue.provide_buffer_chain(&mut buffer_chain);
5253match res {
54Err(ErrorCode::NOMEM) => {
55// Hand back the buffer, the queue MUST NOT write partial
56 // buffer chains
57let buf = buffer_chain[0].take().unwrap().buf;
58Err((buf, ErrorCode::NOMEM))
59 }
60Err(e) => panic!("Unexpected error {:?}", e),
61Ok(()) => {
62let mut cap = self.buffer_capacity.get();
63 cap += len;
64self.buffer_capacity.set(cap);
65Ok(cap)
66 }
67 }
68 }
6970fn buffer_chain_callback(
71&self,
72 buffer_chain: &mut [Option<VirtqueueBuffer<'b>>],
73 bytes_used: usize,
74 ) {
75// Disable further callbacks, until we're sure we need them
76 //
77 // The used buffers should stay in the queue until a client is
78 // ready to consume them
79self.virtqueue.disable_used_callbacks();
8081// We only have buffer chains of a single buffer
82let buf = buffer_chain[0].take().unwrap().buf;
8384// We have taken out a buffer, hence decrease the available capacity
85assert!(self.buffer_capacity.get() >= buf.len());
8687// It could've happened that we don't require the callback any
88 // more, hence check beforehand
89let cont = if self.callback_pending.get() {
90// The callback is no longer pending
91self.callback_pending.set(false);
9293let mut u32randiter = buf[0..bytes_used].chunks(4).filter_map(|slice| {
94if slice.len() < 4 {
95None
96} else {
97Some(u32::from_le_bytes([slice[0], slice[1], slice[2], slice[3]]))
98 }
99 });
100101// For now we don't use left-over randomness and assume the
102 // client has consumed the entire iterator
103self.client
104 .map(|client| client.randomness_available(&mut u32randiter, Ok(())))
105 .unwrap_or(RngCont::Done)
106 } else {
107 RngCont::Done
108 };
109110if let RngCont::More = cont {
111// Returning more is the equivalent of calling .get() on
112 // the Rng trait.
113114 // TODO: what if this call fails?
115let _ = self.get();
116 }
117118// In any case, reinsert the buffer for further processing
119self.provide_buffer(buf).expect("Buffer reinsertion failed");
120 }
121}
122123impl<'a> Rng<'a> for VirtIORng<'a, '_> {
124fn get(&self) -> Result<(), ErrorCode> {
125// Minimum buffer capacity must be 4 bytes for a single 32-bit
126 // word
127if self.buffer_capacity.get() < 4 {
128Err(ErrorCode::FAIL)
129 } else if self.client.is_none() {
130Err(ErrorCode::FAIL)
131 } else if self.callback_pending.get() {
132Err(ErrorCode::OFF)
133 } else if self.virtqueue.used_descriptor_chains_count() < 1 {
134// There is no buffer ready in the queue, so let's rely
135 // purely on queue callbacks to notify us of the next
136 // incoming one
137self.callback_pending.set(true);
138self.virtqueue.enable_used_callbacks();
139Ok(())
140 } else {
141// There is a buffer in the virtqueue, get it and return
142 // it to a client in a deferred call
143self.callback_pending.set(true);
144self.deferred_call.set();
145Ok(())
146 }
147 }
148149fn cancel(&self) -> Result<(), ErrorCode> {
150// Cancel by setting the callback_pending flag to false which
151 // MUST be checked prior to every callback
152self.callback_pending.set(false);
153154// For efficiency reasons, also unsubscribe from the virtqueue
155 // callbacks, which will let the buffers remain in the queue
156 // for future use
157self.virtqueue.disable_used_callbacks();
158159Ok(())
160 }
161162fn set_client(&self, client: &'a dyn RngClient) {
163self.client.set(client);
164 }
165}
166167impl<'b> SplitVirtqueueClient<'b> for VirtIORng<'_, 'b> {
168fn buffer_chain_ready(
169&self,
170 _queue_number: u32,
171 buffer_chain: &mut [Option<VirtqueueBuffer<'b>>],
172 bytes_used: usize,
173 ) {
174self.buffer_chain_callback(buffer_chain, bytes_used)
175 }
176}
177178impl DeferredCallClient for VirtIORng<'_, '_> {
179fn register(&'static self) {
180self.deferred_call.register(self);
181 }
182183fn handle_deferred_call(&self) {
184// Try to extract a descriptor chain
185if let Some((mut chain, bytes_used)) = self.virtqueue.pop_used_buffer_chain() {
186self.buffer_chain_callback(&mut chain, bytes_used)
187 } else {
188// If we don't get a buffer, this must be a race condition
189 // which should not occur
190 //
191 // Prior to setting a deferred call, all virtqueue
192 // interrupts must be disabled so that no used buffer is
193 // removed before the deferred call callback
194panic!("VirtIO RNG: deferred call callback with empty queue");
195 }
196 }
197}
198199impl VirtIODeviceDriver for VirtIORng<'_, '_> {
200fn negotiate_features(&self, _offered_features: u64) -> Option<u64> {
201// We don't support any special features and do not care about
202 // what the device offers.
203Some(0)
204 }
205206fn device_type(&self) -> VirtIODeviceType {
207 VirtIODeviceType::EntropySource
208 }
209}