Skip to main content

axdriver/
lib.rs

1//! [ArceOS](https://github.com/arceos-org/arceos) device drivers.
2//!
3//! # Usage
4//!
5//! All detected devices are composed into a large struct [`AllDevices`]
6//! and returned by the [`init_drivers`] function. The upperlayer subsystems
7//! (e.g., the network stack) may unpack the struct to get the specified device
8//! driver they want.
9//!
10//! For each device category (i.e., net, block, display, etc.), an unified type
11//! is used to represent all devices in that category. Currently, there are 3
12//! categories: [`AxNetDevice`], [`AxBlockDevice`], and [`AxDisplayDevice`].
13//!
14//! # Concepts
15//!
16//! This crate supports two device models depending on the `dyn` feature:
17//!
18//! - **Static**: The type of all devices is static, it is determined at compile
19//!   time by corresponding cargo features. For example, [`AxNetDevice`] will be
20//!   an alias of [`VirtioNetDev`] if the `virtio-net` feature is enabled. This
21//!   model provides the best performance as it avoids dynamic dispatch. But on
22//!   limitation, only one device instance is supported for each device category.
23//! - **Dynamic**: All device instance is using [trait objects] and wrapped in a
24//!   `Box<dyn Trait>`. For example, [`AxNetDevice`] will be [`Box<dyn NetDriverOps>`].
25//!   When call a method provided by the device, it uses [dynamic dispatch][dyn]
26//!   that may introduce a little overhead. But on the other hand, it is more
27//!   flexible, multiple instances of each device category are supported.
28//!
29//! # Supported Devices
30//!
31//! | Device Category | Cargo Feature | Description |
32//! |-|-|-|
33//! | Block | `ramdisk` | A RAM disk that stores data in a vector |
34//! | Block | `virtio-blk` | VirtIO block device |
35//! | Network | `virtio-net` | VirtIO network device |
36//! | Display | `virtio-gpu` | VirtIO graphics device |
37//!
38//! # Other Cargo Features
39//!
40//! - `dyn`: use the dynamic device model (see above).
41//! - `bus-mmio`: use device tree to probe all MMIO devices.
42//! - `bus-pci`: use PCI bus to probe all PCI devices. This feature is
43//!   enabled by default.
44//! - `virtio`: use VirtIO devices. This is enabled if any of `virtio-blk`,
45//!   `virtio-net` or `virtio-gpu` is enabled.
46//! - `net`: use network devices. This is enabled if any feature of network
47//!   devices is selected. If this feature is enabled without any network device
48//!   features, a dummy struct is used for [`AxNetDevice`].
49//! - `block`: use block storage devices. Similar to the `net` feature.
50//! - `display`: use graphics display devices. Similar to the `net` feature.
51//!
52//! [`VirtioNetDev`]: axdriver_virtio::VirtIoNetDev
53//! [`Box<dyn NetDriverOps>`]: axdriver_net::NetDriverOps
54//! [trait objects]: https://doc.rust-lang.org/book/ch17-02-trait-objects.html
55//! [dyn]: https://doc.rust-lang.org/std/keyword.dyn.html
56
57#![no_std]
58#![feature(doc_cfg)]
59#![feature(associated_type_defaults)]
60
61#[macro_use]
62extern crate log;
63
64#[cfg(feature = "dyn")]
65extern crate alloc;
66
67#[macro_use]
68mod macros;
69
70#[cfg(not(feature = "dyn"))]
71mod bus;
72mod drivers;
73mod dummy;
74mod structs;
75
76#[cfg(feature = "virtio")]
77mod virtio;
78
79#[cfg(feature = "ixgbe")]
80mod ixgbe;
81
82#[cfg(feature = "dyn")]
83pub mod dyn_drivers;
84
85#[cfg(feature = "dyn")]
86pub use dyn_drivers::setup;
87
88pub mod prelude;
89
90#[allow(unused_imports)]
91use self::prelude::*;
92pub use self::structs::{AxDeviceContainer, AxDeviceEnum};
93
94#[cfg(feature = "block")]
95pub use self::structs::AxBlockDevice;
96#[cfg(feature = "display")]
97pub use self::structs::AxDisplayDevice;
98#[cfg(feature = "net")]
99pub use self::structs::AxNetDevice;
100
101/// A structure that contains all device drivers, organized by their category.
102#[derive(Default)]
103pub struct AllDevices {
104    /// All network device drivers.
105    #[cfg(feature = "net")]
106    pub net: AxDeviceContainer<AxNetDevice>,
107    /// All block device drivers.
108    #[cfg(feature = "block")]
109    pub block: AxDeviceContainer<AxBlockDevice>,
110    /// All graphics device drivers.
111    #[cfg(feature = "display")]
112    pub display: AxDeviceContainer<AxDisplayDevice>,
113    /// All input device drivers.
114    #[cfg(feature = "input")]
115    pub input: AxDeviceContainer<AxInputDevice>,
116    /// All vsock device drivers.
117    #[cfg(feature = "vsock")]
118    pub vsock: AxDeviceContainer<AxVsockDevice>,
119}
120
121impl AllDevices {
122    /// Returns the device model used, either `dyn` or `static`.
123    ///
124    /// See the [crate-level documentation](crate) for more details.
125    pub const fn device_model() -> &'static str {
126        if cfg!(feature = "dyn") {
127            "dyn"
128        } else {
129            "static"
130        }
131    }
132
133    /// Probes all supported devices.
134    fn probe(&mut self) {
135        #[cfg(feature = "dyn")]
136        for dev in dyn_drivers::probe_all_devices() {
137            self.add_device(dev);
138        }
139        #[cfg(not(feature = "dyn"))]
140        {
141            for_each_drivers!(type Driver, {
142                if let Some(dev) = Driver::probe_global() {
143                    info!(
144                        "registered a new {:?} device: {:?}",
145                        dev.device_type(),
146                        dev.device_name(),
147                    );
148                    self.add_device(dev);
149                }
150            });
151
152            self.probe_bus_devices();
153        }
154    }
155
156    /// Adds one device into the corresponding container, according to its device category.
157    #[allow(dead_code)]
158    fn add_device(&mut self, dev: AxDeviceEnum) {
159        match dev {
160            #[cfg(feature = "net")]
161            AxDeviceEnum::Net(dev) => self.net.push(dev),
162            #[cfg(feature = "block")]
163            AxDeviceEnum::Block(dev) => self.block.push(dev),
164            #[cfg(feature = "display")]
165            AxDeviceEnum::Display(dev) => self.display.push(dev),
166            #[cfg(feature = "input")]
167            AxDeviceEnum::Input(dev) => self.input.push(dev),
168            #[cfg(feature = "vsock")]
169            AxDeviceEnum::Vsock(dev) => self.vsock.push(dev),
170        }
171    }
172}
173
174/// Probes and initializes all device drivers, returns the [`AllDevices`] struct.
175pub fn init_drivers() -> AllDevices {
176    info!("Initialize device drivers...");
177    info!("  device model: {}", AllDevices::device_model());
178
179    let mut all_devs = AllDevices::default();
180    all_devs.probe();
181
182    #[cfg(feature = "net")]
183    {
184        debug!("number of NICs: {}", all_devs.net.len());
185        for (i, dev) in all_devs.net.iter().enumerate() {
186            assert_eq!(dev.device_type(), DeviceType::Net);
187            debug!("  NIC {}: {:?}", i, dev.device_name());
188        }
189    }
190    #[cfg(feature = "block")]
191    {
192        debug!("number of block devices: {}", all_devs.block.len());
193        for (i, dev) in all_devs.block.iter().enumerate() {
194            assert_eq!(dev.device_type(), DeviceType::Block);
195            debug!("  block device {}: {:?}", i, dev.device_name());
196        }
197    }
198    #[cfg(feature = "display")]
199    {
200        debug!("number of graphics devices: {}", all_devs.display.len());
201        for (i, dev) in all_devs.display.iter().enumerate() {
202            assert_eq!(dev.device_type(), DeviceType::Display);
203            debug!("  graphics device {}: {:?}", i, dev.device_name());
204        }
205    }
206    #[cfg(feature = "input")]
207    {
208        debug!("number of input devices: {}", all_devs.input.len());
209        for (i, dev) in all_devs.input.iter().enumerate() {
210            assert_eq!(dev.device_type(), DeviceType::Input);
211            debug!("  input device {}: {:?}", i, dev.device_name());
212        }
213    }
214    #[cfg(feature = "vsock")]
215    {
216        debug!("number of vsock devices: {}", all_devs.vsock.len());
217        for (i, dev) in all_devs.vsock.iter().enumerate() {
218            assert_eq!(dev.device_type(), DeviceType::Vsock);
219            debug!("  vsock device {}: {:?}", i, dev.device_name());
220        }
221    }
222
223    all_devs
224}