Skip to content

Commit

Permalink
Merge pull request #1231 from hermit-os/virtio-spec-mmio-registers
Browse files Browse the repository at this point in the history
refactor(virtio/mmio): migrate `MmioRegisterLayout` to `virtio-spec`
  • Loading branch information
mkroening authored May 29, 2024
2 parents 38c3abc + edbf1df commit 6d8c840
Show file tree
Hide file tree
Showing 8 changed files with 946 additions and 383 deletions.
31 changes: 18 additions & 13 deletions src/arch/riscv64/kernel/devicetree.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
#[cfg(all(feature = "tcp", not(feature = "pci")))]
use core::ptr::NonNull;

use fdt::Fdt;
#[cfg(all(feature = "tcp", not(feature = "pci")))]
use virtio_spec::mmio::{DeviceRegisterVolatileFieldAccess, DeviceRegisters};
#[cfg(all(feature = "tcp", not(feature = "pci")))]
use volatile::VolatileRef;

#[cfg(feature = "gem-net")]
use crate::arch::mm::VirtAddr;
Expand All @@ -9,11 +16,11 @@ use crate::arch::riscv64::kernel::mmio::MmioDriver;
use crate::arch::riscv64::mm::{paging, PhysAddr};
#[cfg(feature = "gem-net")]
use crate::drivers::net::gem;
#[cfg(all(feature = "tcp", not(feature = "pci")))]
use crate::drivers::virtio::transport::mmio::DevId;
#[cfg(all(feature = "tcp", not(feature = "pci"), not(feature = "gem-net")))]
use crate::drivers::virtio::transport::mmio::{self as mmio_virtio, VirtioDriver};
#[cfg(all(feature = "tcp", not(feature = "pci")))]
use crate::drivers::virtio::transport::mmio::{DevId, MmioRegisterLayout};
#[cfg(all(feature = "tcp", not(feature = "pci")))]
use crate::kernel::mmio::register_driver;

static mut PLATFORM_MODEL: Model = Model::Unknown;
Expand Down Expand Up @@ -184,32 +191,30 @@ pub fn init_drivers() {
);

// Verify the first register value to find out if this is really an MMIO magic-value.
let mmio = &mut *(virtio_region.starting_address as *mut MmioRegisterLayout);
let ptr = virtio_region.starting_address as *mut DeviceRegisters;
let mmio = VolatileRef::new(NonNull::new(ptr).unwrap());

let magic = mmio.get_magic_value();
let version = mmio.get_version();
let magic = mmio.as_ptr().magic_value().read().to_ne();
let version = mmio.as_ptr().version().read().to_ne();

const MMIO_MAGIC_VALUE: u32 = 0x74726976;
if magic != MMIO_MAGIC_VALUE {
error!("It's not a MMIO-device at {:#X}", mmio as *const _ as usize);
error!("It's not a MMIO-device at {mmio:p}");
}

if version != 2 {
warn!("Found a leagacy device, which isn't supported");
} else {
// We found a MMIO-device (whose 512-bit address in this structure).
trace!("Found a MMIO-device at {:#X}", mmio as *const _ as usize);
trace!("Found a MMIO-device at {mmio:p}");

// Verify the device-ID to find the network card
let id = mmio.get_device_id();
let id = DevId::from(mmio.as_ptr().device_id().read().to_ne());

if id != DevId::VIRTIO_DEV_ID_NET {
debug!(
"It's not a network card at {:#X}",
mmio as *const _ as usize
);
debug!("It's not a network card at {mmio:p}");
} else {
info!("Found network card at {:#X}", mmio as *const _ as usize);
info!("Found network card at {mmio:p}");

// crate::arch::mm::physicalmem::reserve(
// PhysAddr::from(current_address.align_down(BasePageSize::SIZE as usize)),
Expand Down
111 changes: 48 additions & 63 deletions src/arch/x86_64/kernel/mmio.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
use alloc::string::String;
use alloc::vec::Vec;
use core::ptr::NonNull;
use core::{ptr, str};

use align_address::Align;
use hermit_sync::{without_interrupts, InterruptTicketMutex};
use virtio_spec::mmio::{DeviceRegisterVolatileFieldAccess, DeviceRegisters};
use volatile::VolatileRef;

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::virtio::transport::mmio as mmio_virtio;
use crate::drivers::virtio::transport::mmio::{DevId, MmioRegisterLayout, VirtioDriver};
use crate::drivers::virtio::transport::mmio::{DevId, VirtioDriver};
use crate::env;

pub const MAGIC_VALUE: u32 = 0x74726976;
Expand All @@ -36,9 +39,40 @@ impl MmioDriver {
}
}

unsafe fn check_ptr(ptr: *mut u8) -> Option<VolatileRef<'static, DeviceRegisters>> {
// Verify the first register value to find out if this is really an MMIO magic-value.
let mmio = unsafe { VolatileRef::new(NonNull::new(ptr.cast::<DeviceRegisters>()).unwrap()) };

let magic = mmio.as_ptr().magic_value().read().to_ne();
let version = mmio.as_ptr().version().read().to_ne();

if magic != MAGIC_VALUE {
trace!("It's not a MMIO-device at {mmio:p}");
return None;
}

if version != 2 {
trace!("Found a legacy device, which isn't supported");
return None;
}

// We found a MMIO-device (whose 512-bit address in this structure).
trace!("Found a MMIO-device at {mmio:p}");

// Verify the device-ID to find the network card
let id = DevId::from(mmio.as_ptr().device_id().read().to_ne());

if id != DevId::VIRTIO_DEV_ID_NET {
trace!("It's not a network card at {mmio:p}");
return None;
}

Some(mmio)
}

fn check_linux_args(
linux_mmio: &'static [String],
) -> Result<(&'static mut MmioRegisterLayout, u8), &'static str> {
) -> Result<(VolatileRef<'static, DeviceRegisters>, u8), &'static str> {
let virtual_address =
crate::arch::mm::virtualmem::allocate(BasePageSize::SIZE as usize).unwrap();

Expand Down Expand Up @@ -66,37 +100,12 @@ fn check_linux_args(
flags,
);

// Verify the first register value to find out if this is really an MMIO magic-value.
let mmio = unsafe {
&mut *(ptr::with_exposed_provenance_mut::<MmioRegisterLayout>(
virtual_address.as_usize()
| (current_address & (BasePageSize::SIZE as usize - 1)),
))
};

let magic = mmio.get_magic_value();
let version = mmio.get_version();

if magic != MAGIC_VALUE {
trace!("It's not a MMIO-device at {mmio:p}");
continue;
}

if version != 2 {
trace!("Found a legacy device, which isn't supported");
continue;
}

// We found a MMIO-device (whose 512-bit address in this structure).
trace!("Found a MMIO-device at {mmio:p}");

// Verify the device-ID to find the network card
let id = mmio.get_device_id();

if id != DevId::VIRTIO_DEV_ID_NET {
trace!("It's not a network card at {mmio:p}");
let addr = virtual_address.as_usize()
| (current_address & (BasePageSize::SIZE as usize - 1));
let ptr = ptr::with_exposed_provenance_mut(addr);
let Some(mmio) = (unsafe { check_ptr(ptr) }) else {
continue;
}
};

crate::arch::mm::physicalmem::reserve(
PhysAddr::from(current_address.align_down(BasePageSize::SIZE as usize)),
Expand All @@ -117,7 +126,7 @@ fn check_linux_args(
Err("Network card not found!")
}

fn guess_device() -> Result<(&'static mut MmioRegisterLayout, u8), &'static str> {
fn guess_device() -> Result<(VolatileRef<'static, DeviceRegisters>, u8), &'static str> {
// Trigger page mapping in the first iteration!
let mut current_page = 0;
let virtual_address =
Expand All @@ -144,36 +153,12 @@ fn guess_device() -> Result<(&'static mut MmioRegisterLayout, u8), &'static str>
current_page = current_address / BasePageSize::SIZE as usize;
}

// Verify the first register value to find out if this is really an MMIO magic-value.
let mmio = unsafe {
&mut *(ptr::with_exposed_provenance_mut::<MmioRegisterLayout>(
virtual_address.as_usize() | (current_address & (BasePageSize::SIZE as usize - 1)),
))
};

let magic = mmio.get_magic_value();
let version = mmio.get_version();

if magic != MAGIC_VALUE {
trace!("It's not a MMIO-device at {mmio:p}");
let addr =
virtual_address.as_usize() | (current_address & (BasePageSize::SIZE as usize - 1));
let ptr = ptr::with_exposed_provenance_mut(addr);
let Some(mmio) = (unsafe { check_ptr(ptr) }) else {
continue;
}

if version != 2 {
trace!("Found a legacy device, which isn't supported");
continue;
}

// We found a MMIO-device (whose 512-bit address in this structure).
trace!("Found a MMIO-device at {mmio:p}");

// Verify the device-ID to find the network card
let id = mmio.get_device_id();

if id != DevId::VIRTIO_DEV_ID_NET {
trace!("It's not a network card at {mmio:p}");
continue;
}
};

info!("Found network card at {mmio:p}");

Expand All @@ -193,7 +178,7 @@ fn guess_device() -> Result<(&'static mut MmioRegisterLayout, u8), &'static str>

/// Tries to find the network device within the specified address range.
/// Returns a reference to it within the Ok() if successful or an Err() on failure.
fn detect_network() -> Result<(&'static mut MmioRegisterLayout, u8), &'static str> {
fn detect_network() -> Result<(VolatileRef<'static, DeviceRegisters>, u8), &'static str> {
let linux_mmio = env::mmio();

if !linux_mmio.is_empty() {
Expand Down
24 changes: 16 additions & 8 deletions src/drivers/net/virtio_mmio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
use alloc::rc::Rc;
use alloc::vec::Vec;
use core::ptr;
use core::ptr::read_volatile;
use core::str::FromStr;
use core::sync::atomic::{fence, Ordering};

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

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

/// Virtio's network device configuration structure.
Expand Down Expand Up @@ -110,18 +111,25 @@ impl NetDevCfgRaw {
impl VirtioNetDriver {
pub fn new(
dev_id: u16,
registers: &'static mut MmioRegisterLayout,
mut registers: VolatileRef<'static, DeviceRegisters>,
irq: u8,
) -> Result<Self, VirtioNetError> {
let dev_cfg_raw: &'static NetDevCfgRaw =
unsafe { &*(ptr::with_exposed_provenance(ptr::from_ref(registers).addr() + 0xFC)) };
let dev_cfg_raw: &'static NetDevCfgRaw = unsafe {
&*registers
.borrow_mut()
.as_mut_ptr()
.config_generation()
.as_raw_ptr()
.cast::<NetDevCfgRaw>()
.as_ptr()
};
let dev_cfg = NetDevCfg {
raw: dev_cfg_raw,
dev_id,
features: virtio_spec::net::F::empty(),
};
let isr_stat = IsrStatus::new(registers);
let notif_cfg = NotifCfg::new(registers);
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()
Expand Down Expand Up @@ -159,7 +167,7 @@ impl VirtioNetDriver {
/// [VirtioNetDriver](structs.virtionetdriver.html) or an [VirtioError](enums.virtioerror.html).
pub fn init(
dev_id: u16,
registers: &'static mut MmioRegisterLayout,
registers: VolatileRef<'static, DeviceRegisters>,
irq_no: u8,
) -> Result<VirtioNetDriver, VirtioError> {
if let Ok(mut drv) = VirtioNetDriver::new(dev_id, registers, irq_no) {
Expand Down
Loading

0 comments on commit 6d8c840

Please sign in to comment.