Skip to content

Commit

Permalink
Merge pull request #1268 from hermit-os/net-config
Browse files Browse the repository at this point in the history
refactor(net/virtio): migrate `NetDevCfgRaw` to virtio-spec
  • Loading branch information
mkroening authored Jun 10, 2024
2 parents 48645aa + 1323f2c commit b71107d
Show file tree
Hide file tree
Showing 15 changed files with 255 additions and 302 deletions.
2 changes: 1 addition & 1 deletion src/arch/aarch64/kernel/mmio.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use hermit_sync::InterruptTicketMutex;

use crate::drivers::net::virtio_net::VirtioNetDriver;
use crate::drivers::net::virtio::VirtioNetDriver;

pub(crate) fn get_network_driver() -> Option<&'static InterruptTicketMutex<VirtioNetDriver>> {
None
Expand Down
2 changes: 1 addition & 1 deletion src/arch/riscv64/kernel/mmio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use hermit_sync::InterruptSpinMutex;
#[cfg(feature = "gem-net")]
use crate::drivers::net::gem::GEMDriver;
#[cfg(not(feature = "gem-net"))]
use crate::drivers::net::virtio_net::VirtioNetDriver;
use crate::drivers::net::virtio::VirtioNetDriver;

static mut MMIO_DRIVERS: Vec<MmioDriver> = Vec::new();

Expand Down
2 changes: 1 addition & 1 deletion src/arch/x86_64/kernel/mmio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::arch::x86_64::mm::paging::{
BasePageSize, PageSize, PageTableEntryFlags, PageTableEntryFlagsExt,
};
use crate::arch::x86_64::mm::{paging, PhysAddr};
use crate::drivers::net::virtio_net::VirtioNetDriver;
use crate::drivers::net::virtio::VirtioNetDriver;
use crate::drivers::virtio::transport::mmio as mmio_virtio;
use crate::drivers::virtio::transport::mmio::VirtioDriver;
use crate::env;
Expand Down
6 changes: 1 addition & 5 deletions src/drivers/net/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@
pub mod gem;
#[cfg(feature = "rtl8139")]
pub mod rtl8139;
#[cfg(all(not(feature = "pci"), not(feature = "rtl8139")))]
pub mod virtio_mmio;
#[cfg(not(feature = "rtl8139"))]
pub mod virtio_net;
#[cfg(all(feature = "pci", not(feature = "rtl8139")))]
pub mod virtio_pci;
pub mod virtio;

use smoltcp::phy::ChecksumCapabilities;

Expand Down
95 changes: 95 additions & 0 deletions src/drivers/net/virtio/mmio.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
//! A module containing a virtio network driver.
//!
//! The module contains ...

use alloc::rc::Rc;
use alloc::vec::Vec;
use core::str::FromStr;

use smoltcp::phy::ChecksumCapabilities;
use virtio_spec::mmio::{DeviceRegisterVolatileFieldAccess, DeviceRegisters};
use volatile::VolatileRef;

use crate::drivers::net::virtio::{CtrlQueue, NetDevCfg, RxQueues, TxQueues, VirtioNetDriver};
use crate::drivers::virtio::error::{VirtioError, VirtioNetError};
use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg};
use crate::drivers::virtio::virtqueue::Virtq;

// Backend-dependent interface for Virtio network driver
impl VirtioNetDriver {
pub fn new(
dev_id: u16,
mut registers: VolatileRef<'static, DeviceRegisters>,
irq: u8,
) -> Result<Self, VirtioNetError> {
let dev_cfg_raw: &'static virtio_spec::net::Config = unsafe {
&*registers
.borrow_mut()
.as_mut_ptr()
.config()
.as_raw_ptr()
.cast::<virtio_spec::net::Config>()
.as_ptr()
};
let dev_cfg_raw = VolatileRef::from_ref(dev_cfg_raw);
let dev_cfg = NetDevCfg {
raw: dev_cfg_raw,
dev_id,
features: virtio_spec::net::F::empty(),
};
let isr_stat = IsrStatus::new(registers.borrow_mut());
let notif_cfg = NotifCfg::new(registers.borrow_mut());

let mtu = if let Some(my_mtu) = hermit_var!("HERMIT_MTU") {
u16::from_str(&my_mtu).unwrap()
} else {
// fallback to the default MTU
1514
};

Ok(VirtioNetDriver {
dev_cfg,
com_cfg: ComCfg::new(registers, 1),
isr_stat,
notif_cfg,
ctrl_vq: CtrlQueue::new(None),
recv_vqs: RxQueues::new(Vec::<Rc<dyn Virtq>>::new(), false),
send_vqs: TxQueues::new(Vec::<Rc<dyn Virtq>>::new(), Vec::new(), false),
num_vqs: 0,
irq,
mtu,
checksums: ChecksumCapabilities::default(),
})
}

pub fn print_information(&mut self) {
self.com_cfg.print_information();
if self.dev_status() == virtio_spec::net::S::LINK_UP {
info!("The link of the network device is up!");
}
}

/// Initializes virtio network device by mapping configuration layout to
/// respective structs (configuration structs are:
///
/// Returns a driver instance of
/// [VirtioNetDriver](structs.virtionetdriver.html) or an [VirtioError](enums.virtioerror.html).
pub fn init(
dev_id: u16,
registers: VolatileRef<'static, DeviceRegisters>,
irq_no: u8,
) -> Result<VirtioNetDriver, VirtioError> {
if let Ok(mut drv) = VirtioNetDriver::new(dev_id, registers, irq_no) {
match drv.init_dev() {
Err(error_code) => Err(VirtioError::NetDriver(error_code)),
_ => {
drv.print_information();
Ok(drv)
}
}
} else {
error!("Unable to create Driver. Aborting!");
Err(VirtioError::Unknown)
}
}
}
107 changes: 63 additions & 44 deletions src/drivers/net/virtio_net.rs → src/drivers/net/virtio/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@
//!
//! The module contains ...

cfg_if::cfg_if! {
if #[cfg(feature = "pci")] {
mod pci;
} else {
mod mmio;
}
}

use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::vec::Vec;
Expand All @@ -12,18 +20,16 @@ use align_address::Align;
use pci_types::InterruptLine;
use smoltcp::phy::{Checksum, ChecksumCapabilities};
use smoltcp::wire::{EthernetFrame, Ipv4Packet, Ipv6Packet, ETHERNET_HEADER_LEN};
use virtio_spec::net::{Hdr, HdrF};
use virtio_spec::net::{ConfigVolatileFieldAccess, Hdr, HdrF};
use virtio_spec::FeatureBits;
use volatile::access::ReadOnly;
use volatile::VolatileRef;

use self::constants::{Status, MAX_NUM_VQ};
use self::constants::MAX_NUM_VQ;
use self::error::VirtioNetError;
#[cfg(not(target_arch = "riscv64"))]
use crate::arch::kernel::core_local::increment_irq_counter;
use crate::config::VIRTIO_MAX_QUEUE_SIZE;
#[cfg(not(feature = "pci"))]
use crate::drivers::net::virtio_mmio::NetDevCfgRaw;
#[cfg(feature = "pci")]
use crate::drivers::net::virtio_pci::NetDevCfgRaw;
use crate::drivers::net::NetworkDriver;
#[cfg(not(feature = "pci"))]
use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg};
Expand All @@ -38,7 +44,7 @@ use crate::executor::device::{RxToken, TxToken};
/// Handling the right access to fields, as some are read-only
/// for the driver.
pub(crate) struct NetDevCfg {
pub raw: &'static NetDevCfgRaw,
pub raw: VolatileRef<'static, virtio_spec::net::Config, ReadOnly>,
pub dev_id: u16,
pub features: virtio_spec::net::F,
}
Expand Down Expand Up @@ -154,7 +160,7 @@ impl RxQueues {
(1514 + mem::size_of::<Hdr>())
.align_up(core::mem::size_of::<crossbeam_utils::CachePadded<u8>>())
} else {
dev_cfg.raw.get_mtu() as usize + mem::size_of::<Hdr>()
dev_cfg.raw.as_ptr().mtu().read().to_ne() as usize + mem::size_of::<Hdr>()
};

// See Virtio specification v1.1 - 5.1.6.3.1
Expand Down Expand Up @@ -318,8 +324,10 @@ impl TxQueues {
// Header and data are added as ONE output descriptor to the transmitvq.
// Hence we are interpreting this, as the fact, that send packets must be inside a single descriptor.
// As usize is currently safe as the minimal usize is defined as 16bit in rust.
let buff_def =
Bytes::new(mem::size_of::<Hdr>() + dev_cfg.raw.get_mtu() as usize).unwrap();
let buff_def = Bytes::new(
mem::size_of::<Hdr>() + dev_cfg.raw.as_ptr().mtu().read().to_ne() as usize,
)
.unwrap();
let spec = BuffSpec::Single(buff_def);

let num_buff: u16 = vq.size().into();
Expand Down Expand Up @@ -421,7 +429,14 @@ impl NetworkDriver for VirtioNetDriver {
/// If VIRTIO_NET_F_MAC is not set, the function panics currently!
fn get_mac_address(&self) -> [u8; 6] {
if self.dev_cfg.features.contains(virtio_spec::net::F::MAC) {
self.dev_cfg.raw.get_mac()
loop {
let before = self.com_cfg.config_generation();
let mac = self.dev_cfg.raw.as_ptr().mac().read();
let after = self.com_cfg.config_generation();
if before == after {
break mac;
}
}
} else {
unreachable!("Currently VIRTIO_NET_F_MAC must be negotiated!")
}
Expand Down Expand Up @@ -637,11 +652,11 @@ impl VirtioNetDriver {
/// Returns the current status of the device, if VIRTIO_NET_F_STATUS
/// has been negotiated. Otherwise assumes an active device.
#[cfg(not(feature = "pci"))]
pub fn dev_status(&self) -> u16 {
pub fn dev_status(&self) -> virtio_spec::net::S {
if self.dev_cfg.features.contains(virtio_spec::net::F::STATUS) {
self.dev_cfg.raw.get_status()
self.dev_cfg.raw.as_ptr().status().read()
} else {
u16::from(Status::VIRTIO_NET_S_LINK_UP)
virtio_spec::net::S::LINK_UP
}
}

Expand All @@ -650,8 +665,12 @@ impl VirtioNetDriver {
#[cfg(feature = "pci")]
pub fn is_link_up(&self) -> bool {
if self.dev_cfg.features.contains(virtio_spec::net::F::STATUS) {
self.dev_cfg.raw.get_status() & u16::from(Status::VIRTIO_NET_S_LINK_UP)
== u16::from(Status::VIRTIO_NET_S_LINK_UP)
self.dev_cfg
.raw
.as_ptr()
.status()
.read()
.contains(virtio_spec::net::S::LINK_UP)
} else {
true
}
Expand All @@ -660,8 +679,12 @@ impl VirtioNetDriver {
#[allow(dead_code)]
pub fn is_announce(&self) -> bool {
if self.dev_cfg.features.contains(virtio_spec::net::F::STATUS) {
self.dev_cfg.raw.get_status() & u16::from(Status::VIRTIO_NET_S_ANNOUNCE)
== u16::from(Status::VIRTIO_NET_S_ANNOUNCE)
self.dev_cfg
.raw
.as_ptr()
.status()
.read()
.contains(virtio_spec::net::S::ANNOUNCE)
} else {
false
}
Expand All @@ -675,7 +698,12 @@ impl VirtioNetDriver {
#[allow(dead_code)]
pub fn get_max_vq_pairs(&self) -> u16 {
if self.dev_cfg.features.contains(virtio_spec::net::F::MQ) {
self.dev_cfg.raw.get_max_virtqueue_pairs()
self.dev_cfg
.raw
.as_ptr()
.max_virtqueue_pairs()
.read()
.to_ne()
} else {
1
}
Expand Down Expand Up @@ -838,7 +866,7 @@ impl VirtioNetDriver {
debug!("{:?}", self.checksums);

if self.dev_cfg.features.contains(virtio_spec::net::F::MTU) {
self.mtu = self.dev_cfg.raw.get_mtu();
self.mtu = self.dev_cfg.raw.as_ptr().mtu().read().to_ne();
}

Ok(())
Expand Down Expand Up @@ -924,10 +952,23 @@ impl VirtioNetDriver {
// - the num_queues is found in the ComCfg struct of the device and defines the maximal number
// of supported queues.
if self.dev_cfg.features.contains(virtio_spec::net::F::MQ) {
if self.dev_cfg.raw.get_max_virtqueue_pairs() * 2 >= MAX_NUM_VQ {
if self
.dev_cfg
.raw
.as_ptr()
.max_virtqueue_pairs()
.read()
.to_ne() * 2 >= MAX_NUM_VQ
{
self.num_vqs = MAX_NUM_VQ;
} else {
self.num_vqs = self.dev_cfg.raw.get_max_virtqueue_pairs() * 2;
self.num_vqs = self
.dev_cfg
.raw
.as_ptr()
.max_virtqueue_pairs()
.read()
.to_ne() * 2;
}
} else {
// Minimal number of virtqueues defined in the standard v1.1. - 5.1.5 Step 1
Expand Down Expand Up @@ -1012,28 +1053,6 @@ impl VirtioNetDriver {
pub mod constants {
// Configuration constants
pub const MAX_NUM_VQ: u16 = 2;

/// Enum contains virtio's network device status
/// indiacted in the status field of the device's
/// configuration structure.
///
/// See Virtio specification v1.1. - 5.1.4
#[allow(dead_code, non_camel_case_types)]
#[derive(Copy, Clone, Debug)]
#[repr(u16)]
pub enum Status {
VIRTIO_NET_S_LINK_UP = 1 << 0,
VIRTIO_NET_S_ANNOUNCE = 1 << 1,
}

impl From<Status> for u16 {
fn from(stat: Status) -> Self {
match stat {
Status::VIRTIO_NET_S_LINK_UP => 1,
Status::VIRTIO_NET_S_ANNOUNCE => 2,
}
}
}
}

/// Error module of virtios network driver. Containing the (VirtioNetError)[VirtioNetError]
Expand Down
Loading

0 comments on commit b71107d

Please sign in to comment.