virtio_drivers/device/
rng.rs

1//! Driver for VirtIO random number generator devices.
2use super::common::Feature;
3use crate::{
4    queue::VirtQueue,
5    transport::{InterruptStatus, Transport},
6    Hal, Result,
7};
8
9// VirtioRNG only uses one queue
10const QUEUE_IDX: u16 = 0;
11const QUEUE_SIZE: usize = 8;
12const SUPPORTED_FEATURES: Feature = Feature::RING_INDIRECT_DESC
13    .union(Feature::RING_EVENT_IDX)
14    .union(Feature::VERSION_1);
15
16/// Driver for a VirtIO random number generator device.
17pub struct VirtIORng<H: Hal, T: Transport> {
18    transport: T,
19    queue: VirtQueue<H, QUEUE_SIZE>,
20}
21
22impl<H: Hal, T: Transport> VirtIORng<H, T> {
23    /// Create a new driver with the given transport.
24    pub fn new(mut transport: T) -> Result<Self> {
25        let feat = transport.begin_init(SUPPORTED_FEATURES);
26        let queue = VirtQueue::new(
27            &mut transport,
28            QUEUE_IDX,
29            feat.contains(Feature::RING_INDIRECT_DESC),
30            feat.contains(Feature::RING_EVENT_IDX),
31        )?;
32        transport.finish_init();
33        Ok(Self { transport, queue })
34    }
35
36    /// Request random bytes from the device to be stored into `dst`.
37    pub fn request_entropy(&mut self, dst: &mut [u8]) -> Result<usize> {
38        let num = self
39            .queue
40            .add_notify_wait_pop(&[], &mut [dst], &mut self.transport)?;
41        Ok(num as usize)
42    }
43
44    /// Enable interrupts.
45    pub fn enable_interrupts(&mut self) {
46        self.queue.set_dev_notify(true);
47    }
48
49    /// Disable interrupts.
50    pub fn disable_interrupts(&mut self) {
51        self.queue.set_dev_notify(false);
52    }
53
54    /// Acknowledge interrupt.
55    pub fn ack_interrupt(&mut self) -> InterruptStatus {
56        self.transport.ack_interrupt()
57    }
58}
59
60impl<H: Hal, T: Transport> Drop for VirtIORng<H, T> {
61    fn drop(&mut self) {
62        self.transport.queue_unset(QUEUE_IDX);
63    }
64}