asterinas/kernel/comps/virtio/src/lib.rs

140 lines
4.9 KiB
Rust
Raw Normal View History

2024-01-03 03:22:36 +00:00
// SPDX-License-Identifier: MPL-2.0
//! The virtio of Asterinas.
#![no_std]
#![deny(unsafe_code)]
2024-03-28 07:47:05 +00:00
#![feature(trait_alias)]
2023-08-28 07:03:28 +00:00
#![feature(fn_traits)]
2024-05-06 15:00:48 +00:00
#![feature(linked_list_cursors)]
extern crate alloc;
2023-08-28 07:03:28 +00:00
use alloc::boxed::Box;
2024-11-21 09:23:10 +00:00
use core::hint::spin_loop;
use bitflags::bitflags;
use component::{init_component, ComponentInitError};
2023-08-28 07:03:28 +00:00
use device::{
2024-03-28 07:47:05 +00:00
block::device::BlockDevice,
console::device::ConsoleDevice,
input::device::InputDevice,
network::device::NetworkDevice,
socket::{self, device::SocketDevice},
VirtioDeviceType,
2023-08-28 07:03:28 +00:00
};
use log::{error, warn};
2023-10-28 12:55:44 +00:00
use transport::{mmio::VIRTIO_MMIO_DRIVER, pci::VIRTIO_PCI_DRIVER, DeviceStatus};
2022-11-09 13:20:44 +00:00
2023-08-28 07:03:28 +00:00
use crate::transport::VirtioTransport;
pub mod device;
mod dma_buf;
pub mod queue;
2023-08-28 07:03:28 +00:00
mod transport;
#[init_component]
fn virtio_component_init() -> Result<(), ComponentInitError> {
2023-08-28 07:03:28 +00:00
// Find all devices and register them to the corresponding crate
transport::init();
2024-04-07 15:08:18 +00:00
// For vsock table static init
socket::init();
2023-10-28 12:55:44 +00:00
while let Some(mut transport) = pop_device_transport() {
2023-08-28 07:03:28 +00:00
// Reset device
transport
.write_device_status(DeviceStatus::empty())
.unwrap();
2024-11-21 09:23:10 +00:00
while transport.read_device_status() != DeviceStatus::empty() {
spin_loop();
}
2023-08-28 07:03:28 +00:00
// Set to acknowledge
transport
.write_device_status(DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER)
2023-08-28 07:03:28 +00:00
.unwrap();
// negotiate features
negotiate_features(&mut transport);
2024-11-21 09:23:10 +00:00
if !transport.is_legacy_version() {
// change to features ok status
let status =
DeviceStatus::ACKNOWLEDGE | DeviceStatus::DRIVER | DeviceStatus::FEATURES_OK;
transport.write_device_status(status).unwrap();
}
2023-08-28 07:03:28 +00:00
let device_type = transport.device_type();
let res = match transport.device_type() {
VirtioDeviceType::Block => BlockDevice::init(transport),
VirtioDeviceType::Input => InputDevice::init(transport),
VirtioDeviceType::Network => NetworkDevice::init(transport),
2023-11-08 06:13:15 +00:00
VirtioDeviceType::Console => ConsoleDevice::init(transport),
2024-03-28 02:55:16 +00:00
VirtioDeviceType::Socket => SocketDevice::init(transport),
2023-08-28 07:03:28 +00:00
_ => {
warn!("[Virtio]: Found unimplemented device:{:?}", device_type);
Ok(())
}
2023-08-28 07:03:28 +00:00
};
if res.is_err() {
error!(
"[Virtio]: Device initialization error:{:?}, device type:{:?}",
res, device_type
);
}
}
2023-08-28 07:03:28 +00:00
Ok(())
}
2023-10-28 12:55:44 +00:00
fn pop_device_transport() -> Option<Box<dyn VirtioTransport>> {
if let Some(device) = VIRTIO_PCI_DRIVER.get().unwrap().pop_device_transport() {
2024-11-21 09:23:10 +00:00
return Some(device);
2023-10-28 12:55:44 +00:00
}
if let Some(device) = VIRTIO_MMIO_DRIVER.get().unwrap().pop_device_transport() {
return Some(Box::new(device));
}
None
}
2023-08-28 07:03:28 +00:00
2023-10-28 12:55:44 +00:00
fn negotiate_features(transport: &mut Box<dyn VirtioTransport>) {
let features = transport.read_device_features();
2023-08-28 07:03:28 +00:00
let mask = ((1u64 << 24) - 1) | (((1u64 << 24) - 1) << 50);
let device_specified_features = features & mask;
let device_support_features = match transport.device_type() {
VirtioDeviceType::Network => NetworkDevice::negotiate_features(device_specified_features),
VirtioDeviceType::Block => BlockDevice::negotiate_features(device_specified_features),
VirtioDeviceType::Input => InputDevice::negotiate_features(device_specified_features),
2023-11-08 06:13:15 +00:00
VirtioDeviceType::Console => ConsoleDevice::negotiate_features(device_specified_features),
2024-03-28 02:55:16 +00:00
VirtioDeviceType::Socket => SocketDevice::negotiate_features(device_specified_features),
2023-08-28 07:03:28 +00:00
_ => device_specified_features,
};
let mut support_feature = Feature::from_bits_truncate(features);
support_feature.remove(Feature::RING_EVENT_IDX);
transport
.write_driver_features(features & (support_feature.bits | device_support_features))
2023-08-28 07:03:28 +00:00
.unwrap();
}
bitflags! {
/// all device features, bits 0~23 and 50~63 are specified by device.
/// if using this struct to translate u64, use from_bits_truncate function instead of from_bits
///
struct Feature: u64 {
// device independent
const NOTIFY_ON_EMPTY = 1 << 24; // legacy
const ANY_LAYOUT = 1 << 27; // legacy
const RING_INDIRECT_DESC = 1 << 28;
const RING_EVENT_IDX = 1 << 29;
const UNUSED = 1 << 30; // legacy
const VERSION_1 = 1 << 32; // detect legacy
// since virtio v1.1
const ACCESS_PLATFORM = 1 << 33;
const RING_PACKED = 1 << 34;
const IN_ORDER = 1 << 35;
const ORDER_PLATFORM = 1 << 36;
const SR_IOV = 1 << 37;
const NOTIFICATION_DATA = 1 << 38;
2023-10-28 12:55:44 +00:00
const NOTIF_CONFIG_DATA = 1 << 39;
const RING_RESET = 1 << 40;
}
}