virtio/devices/
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

use kernel::ErrorCode;

pub mod virtio_net;
pub mod virtio_rng;

/// VirtIO Device Types.
///
/// VirtIO is a flexible bus which can be used to expose various kinds of
/// virtual devices, such as network drivers, serial consoles, block devices or
/// random number generators. A VirtIO bus endpoint announces which type of
/// device it represents (and hence also which rules and semantics the VirtIO
/// driver should follow).
///
/// This enum maps the VirtIO device IDs to human-readable variants of an enum,
/// which can be used throughout the code base. Users should not rely on this
/// enum not being extended. Whenever an official device ID is missing, it can
/// be added to this enumeration.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[repr(u32)]
#[non_exhaustive]
pub enum VirtIODeviceType {
    NetworkCard = 1,
    BlockDevice = 2,
    Console = 3,
    EntropySource = 4,
    TraditionalMemoryBallooning = 5,
    IoMemory = 6,
    RPMSG = 7,
    SCSIHost = 8,
    Transport9P = 9,
    Mac80211Wlan = 10,
    RPROCSerial = 11,
    VirtIOCAIF = 12,
    MemoryBalloon = 13,
    GPUDevice = 14,
    TimerClockDevice = 15,
    InputDevice = 16,
    SocketDevice = 17,
    CryptoDevice = 18,
    SignalDistributionModule = 19,
    PstoreDevice = 20,
    IOMMUDevice = 21,
    MemoryDevice = 22,
}

impl VirtIODeviceType {
    /// Try to create a [`VirtIODeviceType`] enum variant from a supplied
    /// numeric device ID.
    pub fn from_device_id(id: u32) -> Option<VirtIODeviceType> {
        use VirtIODeviceType as DT;

        match id {
            1 => Some(DT::NetworkCard),
            2 => Some(DT::BlockDevice),
            3 => Some(DT::Console),
            4 => Some(DT::EntropySource),
            5 => Some(DT::TraditionalMemoryBallooning),
            6 => Some(DT::IoMemory),
            7 => Some(DT::RPMSG),
            8 => Some(DT::SCSIHost),
            9 => Some(DT::Transport9P),
            10 => Some(DT::Mac80211Wlan),
            11 => Some(DT::RPROCSerial),
            12 => Some(DT::VirtIOCAIF),
            13 => Some(DT::MemoryBalloon),
            14 => Some(DT::GPUDevice),
            15 => Some(DT::TimerClockDevice),
            16 => Some(DT::InputDevice),
            17 => Some(DT::SocketDevice),
            18 => Some(DT::CryptoDevice),
            19 => Some(DT::SignalDistributionModule),
            20 => Some(DT::PstoreDevice),
            21 => Some(DT::IOMMUDevice),
            22 => Some(DT::MemoryDevice),
            _ => None,
        }
    }

    /// Convert a [`VirtIODeviceType`] variant to its corresponding device ID.
    pub fn to_device_id(device_type: VirtIODeviceType) -> u32 {
        device_type as u32
    }
}

/// VirtIO Device Driver.
///
/// This trait is to be implemented by drivers for exposed VirtIO devices, using
/// the transports provided in [`crate::transports`] and queues in
/// [`crate::queues`] to communicate with VirtIO devices.
pub trait VirtIODeviceDriver {
    /// VirtIO feature negotiation.
    ///
    /// This function is passed all driver-specific feature bits which the
    /// device exposes. Based on this function, the driver can select which
    /// features to enable through the return value of this function. This
    /// function is executed through the VirtIO transport, potentially before
    /// the device is initialized. As such, implementations of this function
    /// should be pure and only depend on the `offered_features` input
    /// parameter.
    fn negotiate_features(&self, offered_features: u64) -> Option<u64>;

    /// VirtIO device type which the driver supports.
    ///
    /// This function must return the VirtIO device type that the driver is able
    /// to drive. Implementations of this function must be pure and return a
    /// constant value.
    fn device_type(&self) -> VirtIODeviceType;

    /// Hook called before the transport indicates `DRIVER_OK` to the device.
    ///
    /// Because this trait must be object safe, a device cannot convey arbitrary
    /// errors through this interface. When this function returns an error, the
    /// transport will indicate `FAILED` to the device and return the error to
    /// the caller of
    /// [`VirtIOTransport::initialize`](super::transports::VirtIOTransport::initialize).
    /// The driver can store a more elaborate error internally and expose it
    /// through a custom interface.
    ///
    /// A default implementation of this function is provided which does nothing
    /// and returns `Ok(())`.
    fn pre_device_initialization(&self) -> Result<(), ErrorCode> {
        Ok(())
    }

    /// Hook called after the transport indicated `DRIVER_OK` to the device.
    ///
    /// Because this trait must be object safe, a device cannot convey arbitrary
    /// errors through this interface. When this function returns an error, the
    /// transport will **NOT** indicate `FAILED` to the device, but return the
    /// error to the caller of
    /// [`VirtIOTransport::initialize`](super::transports::VirtIOTransport::initialize).
    /// The driver can store a more elaborate error internally and expose it
    /// through a custom interface. The driver remains responsible for any
    /// deinitialization of the device as a result of this error.
    ///
    /// A default implementation of this function is provided which does nothing
    /// and returns `Ok(())`.
    fn device_initialized(&self) -> Result<(), ErrorCode> {
        Ok(())
    }
}