virtio/transports/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! VirtIO transports.
//!
//! This module and its submodules provide abstractions for and implementations
//! of VirtIO transports. For more information, see the documentation of the
//! [`VirtIOTransport`] trait.

use kernel::ErrorCode;

use super::devices::{VirtIODeviceDriver, VirtIODeviceType};
use super::queues::Virtqueue;

pub mod mmio;

#[derive(Debug, Copy, Clone)]
pub enum VirtIOInitializationError {
    /// Device does not identify itself or can be recognized as a VirtIO device.
    NotAVirtIODevice,
    /// An unknown or incompatible VirtIO standard version.
    InvalidVirtIOVersion,
    /// An unknown or incompatible VirtIO transport device version.
    InvalidTransportVersion,
    /// Unknown VirtIO device type (as defined by the [`VirtIODeviceType`] enum).
    UnknownDeviceType(u32),
    /// Driver does not support driving the recognized device type.
    IncompatibleDriverDeviceType(VirtIODeviceType),
    /// Feature negotiation between the device and transport + device driver has
    /// failed.
    ///
    /// The device offered the `offered` features, the driver has either not
    /// accepted this feature set `accepted == None` or has responded with the
    /// `accepted` feature bitset, which the device has subsequently not
    /// acknowledged.
    FeatureNegotiationFailed { offered: u64, accepted: Option<u64> },
    /// The requested [`Virtqueue`] with respective index is not available with
    /// this VirtIO device.
    VirtqueueNotAvailable(usize),
    /// An error was reported by the
    /// [`VirtIODeviceDriver::pre_device_initialization`] function. The device
    /// has been put into the `FAILED` state.
    DriverPreInitializationError(ErrorCode),
    /// An error was reported by the [`VirtIODeviceDriver::device_initialized`]
    /// function. The device status has been previously indicated as `DRIVER_OK`
    /// and the transport has **NOT** put it into the `FAILED` state, although
    /// the driver might have. The initialization has continued as usual,
    /// despite reporting this error, hence it also carries the device type.
    DriverInitializationError(VirtIODeviceType, ErrorCode),
    /// An invariant was violated by the device. This error should not occur
    /// assuming a compliant device, transport and driver implementation.
    DeviceError,
}

/// VirtIO transports.
///
/// VirtIO can be used over multiple different transports, such as over a PCI
/// bus, an MMIO device or channel IO. This trait provides a basic abstraction
/// over such transports.
pub trait VirtIOTransport {
    /// Initialize the VirtIO transport using a device driver instance.
    ///
    /// This function is expected to run the basic initialization routine as
    /// defined for the various VirtIO transports. As part of this routine, it
    /// shall
    ///
    /// - negotiate device features,
    /// - invoke the driver `pre_device_initialization` hook before and
    ///   `device_initialized` hook after announcing the `DRIVER_OK` device
    ///   status flag to the device,
    /// - register the passed [`Virtqueue`]s with the device, calling the
    ///   [`Virtqueue::initialize`] function with the registered queue ID
    ///   _before_ registration,
    /// - as well as perform any other required initialization of the VirtIO
    ///   transport.
    ///
    /// The passed [`Virtqueue`]s are registered with a queue ID matching their
    /// offset in the supplied slice.
    ///
    /// If the initialization fails, it shall report this condition to the
    /// device _(setting `FAILED`) if_ it has started initializing the device
    /// (setting the `ACKNOWLEDGE` device status flag), and return an
    /// appropriate [`VirtIOInitializationError`]. Otherwise, it shall return
    /// the type of device connected to this VirtIO transport.
    fn initialize(
        &self,
        driver: &dyn VirtIODeviceDriver,
        queues: &'static [&'static dyn Virtqueue],
    ) -> Result<VirtIODeviceType, VirtIOInitializationError>;

    /// Notify the device of a changed [`Virtqueue`].
    ///
    /// Whenever a queue has been updated (e.g. move descriptors from the used
    /// to available ring) and these updates shall be made visible to the
    /// driver, the queue can invoke this function, passing its own respective
    /// queue ID.
    fn queue_notify(&self, queue_id: u32);
}