diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dcb46beca0..cf8ed89309 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -269,7 +269,11 @@ jobs: - run: cargo clean working-directory: . - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package vsock qemu ${{ matrix.qemu_flags }} --sudo --devices virtio-vsock-pci - if: matrix.arch != 'riscv64' && matrix.arch != 'aarch64_be' + if: matrix.arch != 'riscv64' + - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package vsock --no-default-features --features hermit/virtio-vsock qemu ${{ matrix.qemu_flags }} --sudo --devices virtio-vsock-mmio --microvm + if: matrix.arch == 'x86_64' + - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package vsock --no-default-features --features hermit/virtio-vsock qemu ${{ matrix.qemu_flags }} --sudo --devices virtio-vsock-mmio + if: matrix.arch != 'x86_64' - run: cargo xtask ci rs --arch ${{ matrix.arch }} --profile ${{ matrix.profile }} ${{ matrix.rs_flags }} --package httpd --features ci,hermit/dhcpv4,hermit/virtio-net qemu ${{ matrix.qemu_flags }} --devices virtio-net-pci if: matrix.arch != 'riscv64' # FIXME: this is broken on QEMU 8.2.2 diff --git a/Cargo.toml b/Cargo.toml index 68fa0e81b4..a99e36fd7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -189,7 +189,7 @@ virtio-console = ["virtio"] virtio-fs = ["virtio", "dep:fuse-abi", "fuse-abi/num_enum"] ## Enables the virtio-vsock driver. -virtio-vsock = ["virtio", "pci"] +virtio-vsock = ["virtio"] #! ### Other Drivers diff --git a/src/arch/aarch64/kernel/mmio.rs b/src/arch/aarch64/kernel/mmio.rs index 3740430242..fd916ab606 100644 --- a/src/arch/aarch64/kernel/mmio.rs +++ b/src/arch/aarch64/kernel/mmio.rs @@ -3,7 +3,11 @@ use core::ptr::NonNull; use align_address::Align; use arm_gic::{IntId, Trigger}; -#[cfg(any(feature = "virtio-console", feature = "virtio-fs"))] +#[cfg(any( + feature = "virtio-console", + feature = "virtio-fs", + feature = "virtio-vsock", +))] use hermit_sync::InterruptTicketMutex; use hermit_sync::without_interrupts; use virtio::mmio::{DeviceRegisters, DeviceRegistersVolatileFieldAccess}; @@ -26,8 +30,11 @@ use crate::drivers::virtio::transport::mmio as mmio_virtio; feature = "virtio-console", feature = "virtio-fs", feature = "virtio-net", + feature = "virtio-vsock", ))] use crate::drivers::virtio::transport::mmio::VirtioDriver; +#[cfg(feature = "virtio-vsock")] +use crate::drivers::vsock::VirtioVsockDriver; #[cfg(feature = "virtio-net")] use crate::executor::device::NETWORK_DEVICE; use crate::init_cell::InitCell; @@ -40,6 +47,8 @@ pub(crate) enum MmioDriver { VirtioConsole(InterruptTicketMutex), #[cfg(feature = "virtio-fs")] VirtioFs(InterruptTicketMutex), + #[cfg(feature = "virtio-vsock")] + VirtioVsock(InterruptTicketMutex), } impl MmioDriver { @@ -56,9 +65,16 @@ impl MmioDriver { Self::VirtioFs(drv) => Some(drv), } } + + #[cfg(feature = "virtio-vsock")] + fn get_vsock_driver(&self) -> Option<&InterruptTicketMutex> { + match self { + Self::VirtioVsock(drv) => Some(drv), + } + } } -#[cfg(any(feature = "virtio-console", feature = "virtio-fs"))] +#[cfg(any(feature = "virtio-console", feature = "virtio-fs", feature = "virtio-vsock"))] pub(crate) fn register_driver(drv: MmioDriver) { MMIO_DRIVERS.with(|mmio_drivers| mmio_drivers.unwrap().push(drv)); } @@ -82,6 +98,14 @@ pub(crate) fn get_filesystem_driver() -> Option<&'static InterruptTicketMutex Option<&'static InterruptTicketMutex> { + MMIO_DRIVERS + .get()? + .iter() + .find_map(|drv| drv.get_vsock_driver()) +} + pub fn init_drivers() { without_interrupts(|| { let Some(fdt) = crate::env::fdt() else { @@ -199,6 +223,10 @@ pub fn init_drivers() { )), #[cfg(feature = "virtio-net")] VirtioDriver::Net(drv) => *NETWORK_DEVICE.lock() = Some(*drv), + #[cfg(feature = "virtio-vsock")] + VirtioDriver::Vsock(drv) => register_driver(MmioDriver::VirtioVsock( + hermit_sync::InterruptTicketMutex::new(*drv), + )), } } } diff --git a/src/arch/riscv64/kernel/devicetree.rs b/src/arch/riscv64/kernel/devicetree.rs index 27e311bddd..c418b27e16 100644 --- a/src/arch/riscv64/kernel/devicetree.rs +++ b/src/arch/riscv64/kernel/devicetree.rs @@ -11,7 +11,11 @@ use volatile::VolatileRef; use crate::arch::riscv64::kernel::interrupts::init_plic; #[cfg(all( - any(feature = "virtio-console", feature = "virtio-fs"), + any( + feature = "virtio-console", + feature = "virtio-fs", + feature = "virtio-vsock", + ), not(feature = "pci"), ))] use crate::arch::riscv64::kernel::mmio::MmioDriver; @@ -33,6 +37,7 @@ use crate::drivers::virtio::transport::mmio as mmio_virtio; feature = "virtio-console", feature = "virtio-fs", feature = "virtio-net", + feature = "virtio-vsock", ), not(feature = "pci"), ))] @@ -41,7 +46,11 @@ use crate::env; #[cfg(all(any(feature = "gem-net", feature = "virtio-net"), not(feature = "pci")))] use crate::executor::device::NETWORK_DEVICE; #[cfg(all( - any(feature = "virtio-console", feature = "virtio-fs"), + any( + feature = "virtio-console", + feature = "virtio-fs", + feature = "virtio-vsock", + ), not(feature = "pci") ))] use crate::kernel::mmio::register_driver; @@ -260,6 +269,12 @@ pub fn init_drivers() { Ok(VirtioDriver::Net(drv)) => { *NETWORK_DEVICE.lock() = Some(*drv); } + #[cfg(feature = "virtio-vsock")] + Ok(VirtioDriver::Vsock(drv)) => { + register_driver(MmioDriver::VirtioVsock( + hermit_sync::InterruptSpinMutex::new(*drv), + )); + } Err(err) => error!("Could not initialize virtio-mmio device: {err}"), } } diff --git a/src/arch/riscv64/kernel/mmio.rs b/src/arch/riscv64/kernel/mmio.rs index f1ca32d5de..10159debe9 100644 --- a/src/arch/riscv64/kernel/mmio.rs +++ b/src/arch/riscv64/kernel/mmio.rs @@ -1,6 +1,10 @@ use alloc::vec::Vec; -#[cfg(any(feature = "virtio-console", feature = "virtio-fs"))] +#[cfg(any( + feature = "virtio-console", + feature = "virtio-fs", + feature = "virtio-vsock", +))] use hermit_sync::InterruptSpinMutex; #[cfg(feature = "virtio-console")] @@ -11,6 +15,8 @@ use crate::drivers::fs::VirtioFsDriver; use crate::drivers::net::gem::GEMDriver; #[cfg(all(not(feature = "gem-net"), feature = "virtio-net"))] use crate::drivers::net::virtio::VirtioNetDriver; +#[cfg(feature = "virtio-vsock")] +use crate::drivers::vsock::VirtioVsockDriver; use crate::init_cell::InitCell; pub(crate) static MMIO_DRIVERS: InitCell> = InitCell::new(Vec::new()); @@ -20,6 +26,8 @@ pub(crate) enum MmioDriver { VirtioConsole(InterruptSpinMutex), #[cfg(feature = "virtio-fs")] VirtioFs(InterruptSpinMutex), + #[cfg(feature = "virtio-vsock")] + VirtioVsock(InterruptSpinMutex), } impl MmioDriver { @@ -36,9 +44,20 @@ impl MmioDriver { Self::VirtioFs(drv) => Some(drv), } } + + #[cfg(feature = "virtio-vsock")] + fn get_vsock_driver(&self) -> Option<&InterruptSpinMutex> { + match self { + Self::VirtioVsock(drv) => Some(drv), + } + } } -#[cfg(any(feature = "virtio-console", feature = "virtio-fs"))] +#[cfg(any( + feature = "virtio-console", + feature = "virtio-fs", + feature = "virtio-vsock", +))] pub(crate) fn register_driver(drv: MmioDriver) { MMIO_DRIVERS.with(|mmio_drivers| mmio_drivers.unwrap().push(drv)); } @@ -64,3 +83,11 @@ pub(crate) fn get_filesystem_driver() -> Option<&'static InterruptSpinMutex Option<&'static InterruptSpinMutex> { + MMIO_DRIVERS + .get()? + .iter() + .find_map(|drv| drv.get_vsock_driver()) +} diff --git a/src/arch/x86_64/kernel/mmio.rs b/src/arch/x86_64/kernel/mmio.rs index 28332f5fc7..0506490763 100644 --- a/src/arch/x86_64/kernel/mmio.rs +++ b/src/arch/x86_64/kernel/mmio.rs @@ -5,7 +5,11 @@ use core::{ptr, str}; use align_address::Align; use free_list::{PageLayout, PageRange}; -#[cfg(any(feature = "virtio-console", feature = "virtio-fs"))] +#[cfg(any( + feature = "virtio-console", + feature = "virtio-fs", + feature = "virtio-vsock", +))] use hermit_sync::InterruptTicketMutex; use hermit_sync::without_interrupts; use memory_addresses::{PhysAddr, VirtAddr}; @@ -26,9 +30,12 @@ use crate::drivers::virtio::transport::mmio as mmio_virtio; #[cfg(any( feature = "virtio-console", feature = "virtio-fs", - feature = "virtio-net" + feature = "virtio-net", + feature = "virtio-vsock", ))] use crate::drivers::virtio::transport::mmio::VirtioDriver; +#[cfg(feature = "virtio-vsock")] +use crate::drivers::vsock::VirtioVsockDriver; use crate::env; #[cfg(any(feature = "rtl8139", feature = "virtio-net"))] use crate::executor::device::NETWORK_DEVICE; @@ -48,6 +55,8 @@ pub(crate) enum MmioDriver { VirtioConsole(InterruptTicketMutex), #[cfg(feature = "virtio-fs")] VirtioFs(InterruptTicketMutex), + #[cfg(feature = "virtio-vsock")] + VirtioVsock(InterruptTicketMutex), } impl MmioDriver { @@ -64,6 +73,13 @@ impl MmioDriver { Self::VirtioFs(drv) => Some(drv), } } + + #[cfg(feature = "virtio-vsock")] + fn get_vsock_driver(&self) -> Option<&InterruptTicketMutex> { + match self { + Self::VirtioVsock(drv) => Some(drv), + } + } } unsafe fn check_ptr(ptr: *mut u8) -> Option> { @@ -210,7 +226,11 @@ fn detect_devices() -> Vec<(VolatileRef<'static, DeviceRegisters>, u8)> { } } -#[cfg(any(feature = "virtio-console", feature = "virtio-fs"))] +#[cfg(any( + feature = "virtio-console", + feature = "virtio-fs", + feature = "virtio-vsock", +))] pub(crate) fn register_driver(drv: MmioDriver) { MMIO_DRIVERS.with(|mmio_drivers| mmio_drivers.unwrap().push(drv)); } @@ -234,6 +254,14 @@ pub(crate) fn get_filesystem_driver() -> Option<&'static InterruptTicketMutex Option<&'static InterruptTicketMutex> { + MMIO_DRIVERS + .get()? + .iter() + .find_map(|drv| drv.get_vsock_driver()) +} + pub(crate) fn init_drivers() { without_interrupts(|| { let devices = detect_devices(); @@ -252,6 +280,10 @@ pub(crate) fn init_drivers() { Ok(VirtioDriver::Net(drv)) => { *NETWORK_DEVICE.lock() = Some(*drv); } + #[cfg(feature = "virtio-vsock")] + Ok(VirtioDriver::Vsock(drv)) => { + register_driver(MmioDriver::VirtioVsock(InterruptTicketMutex::new(*drv))); + } Err(err) => error!("Could not initialize virtio-mmio device: {err}"), } } diff --git a/src/drivers/mmio.rs b/src/drivers/mmio.rs index 5da366f35a..24cee0c67a 100644 --- a/src/drivers/mmio.rs +++ b/src/drivers/mmio.rs @@ -5,11 +5,14 @@ use hashbrown::HashMap; pub(crate) use crate::arch::kernel::mmio::get_console_driver; #[cfg(feature = "virtio-fs")] pub(crate) use crate::arch::kernel::mmio::get_filesystem_driver; +#[cfg(feature = "virtio-vsock")] +pub(crate) use crate::arch::kernel::mmio::get_vsock_driver; #[cfg(any( feature = "virtio-console", all(target_arch = "riscv64", feature = "gem-net", not(feature = "pci")), feature = "virtio-net", feature = "virtio-fs", + feature = "virtio-vsock", ))] use crate::drivers::Driver; use crate::drivers::{InterruptHandlerQueue, InterruptLine}; @@ -71,5 +74,22 @@ pub(crate) fn get_interrupt_handlers() -> HashMap { vq_index: u16, @@ -317,6 +319,8 @@ pub(crate) enum VirtioDriver { Fs(alloc::boxed::Box), #[cfg(feature = "virtio-net")] Net(alloc::boxed::Box), + #[cfg(feature = "virtio-vsock")] + Vsock(alloc::boxed::Box), } #[allow(unused_variables)] @@ -385,13 +389,13 @@ pub(crate) fn init_device( }, #[cfg(feature = "virtio-vsock")] virtio::Id::Vsock => match VirtioVsockDriver::init(dev_id, registers, irq_no) { - Ok(virt_net_drv) => { + Ok(virt_vsock_drv) => { info!("Virtio sock driver initialized."); crate::arch::interrupts::add_irq_name(irq_no, "virtio"); info!("Virtio interrupt handler at line {irq_no}"); - Ok(VirtioDriver::Vsock(virt_vsock_drv)) + Ok(VirtioDriver::Vsock(alloc::boxed::Box::new(virt_vsock_drv))) } Err(virtio_error) => { error!("Virtio sock driver could not be initialized with device"); diff --git a/src/drivers/vsock/mmio.rs b/src/drivers/vsock/mmio.rs new file mode 100644 index 0000000000..071d1735c7 --- /dev/null +++ b/src/drivers/vsock/mmio.rs @@ -0,0 +1,62 @@ +use virtio::vsock::Config; +use virtio::mmio::{DeviceRegisters, DeviceRegistersVolatileFieldAccess}; +use volatile::VolatileRef; + +use crate::drivers::InterruptLine; +use crate::drivers::vsock::{EventQueue, RxQueue, TxQueue, VirtioVsockDriver, VsockDevCfg}; +use crate::drivers::virtio::error::VirtioError; +use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; + +// Backend-dependent interface for Virtio vsock driver +impl VirtioVsockDriver { + pub fn new( + dev_id: u16, + mut registers: VolatileRef<'static, DeviceRegisters>, + irq: InterruptLine, + ) -> Result { + let dev_cfg_raw: &'static Config = unsafe { + &*registers + .borrow_mut() + .as_mut_ptr() + .config() + .as_raw_ptr() + .cast::() + .as_ptr() + }; + let dev_cfg_raw = VolatileRef::from_ref(dev_cfg_raw); + let dev_cfg = VsockDevCfg { + raw: dev_cfg_raw, + dev_id, + features: virtio::vsock::F::empty(), + }; + let isr_stat = IsrStatus::new(registers.borrow_mut()); + let notif_cfg = NotifCfg::new(registers.borrow_mut()); + + Ok(VirtioVsockDriver { + dev_cfg, + com_cfg: ComCfg::new(registers), + isr_stat, + notif_cfg, + irq, + event_vq: EventQueue::new(), + recv_vq: RxQueue::new(), + send_vq: TxQueue::new(), + }) + } + + /// Initializes virtio vsock device by mapping configuration layout to + /// respective structs (configuration structs are: + /// + /// Returns a driver instance of + /// [VirtioVsockDriver](structs.virtionetdriver.html) or an [VirtioError](enums.virtioerror.html). + pub fn init( + dev_id: u16, + registers: VolatileRef<'static, DeviceRegisters>, + irq: InterruptLine, + ) -> Result { + let mut drv = VirtioVsockDriver::new(dev_id, registers, irq)?; + drv.init_dev().map_err(VirtioError::VsockDriver)?; + drv.com_cfg.print_information(); + Ok(drv) + } +} diff --git a/src/drivers/vsock/mod.rs b/src/drivers/vsock/mod.rs index 83253c4d7d..c8b1c550a1 100644 --- a/src/drivers/vsock/mod.rs +++ b/src/drivers/vsock/mod.rs @@ -1,7 +1,13 @@ #![allow(dead_code)] -#[cfg(feature = "pci")] -pub mod pci; +cfg_select! { + feature = "pci" => { + mod pci; + } + _ => { + mod mmio; + } +} use alloc::boxed::Box; use alloc::vec::Vec; @@ -9,21 +15,23 @@ use core::mem; use pci_types::InterruptLine; use smallvec::SmallVec; -use virtio::vsock::Hdr; +use virtio::vsock::{ConfigVolatileFieldAccess, Hdr}; +use volatile::VolatileRef; +use volatile::access::ReadOnly; use super::virtio::virtqueue::VirtQueue; use crate::config::VIRTIO_MAX_QUEUE_SIZE; use crate::drivers::Driver; use crate::drivers::virtio::ControlRegisters; use crate::drivers::virtio::error::VirtioVsockError; +#[cfg(not(feature = "pci"))] +use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; #[cfg(feature = "pci")] use crate::drivers::virtio::transport::pci::{ComCfg, IsrStatus, NotifCfg}; use crate::drivers::virtio::virtqueue::split::SplitVq; use crate::drivers::virtio::virtqueue::{ AvailBufferToken, BufferElem, BufferType, UsedBufferToken, Virtq, }; -#[cfg(feature = "pci")] -use crate::drivers::vsock::pci::VsockDevCfgRaw; use crate::mm::device_alloc::DeviceAlloc; fn fill_queue(vq: &mut VirtQueue, num_packets: u16, packet_size: u32) { @@ -243,7 +251,7 @@ impl EventQueue { /// Handling the right access to fields, as some are read-only /// for the driver. pub(crate) struct VsockDevCfg { - pub raw: &'static VsockDevCfgRaw, + pub raw: VolatileRef<'static, virtio::vsock::Config, ReadOnly>, pub dev_id: u16, pub features: virtio::vsock::F, } @@ -278,7 +286,7 @@ impl VirtioVsockDriver { #[inline] pub fn get_cid(&self) -> u64 { - self.dev_cfg.raw.guest_cid + self.dev_cfg.raw.as_ptr().guest_cid().read().to_ne() } #[cfg(feature = "pci")] diff --git a/src/drivers/vsock/pci.rs b/src/drivers/vsock/pci.rs index 7b2db01f2b..6b3c64c9ed 100644 --- a/src/drivers/vsock/pci.rs +++ b/src/drivers/vsock/pci.rs @@ -1,3 +1,5 @@ +use volatile::VolatileRef; + use crate::arch::pci::PciConfigRegion; use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; @@ -5,20 +7,11 @@ use crate::drivers::virtio::transport::pci; use crate::drivers::virtio::transport::pci::{PciCap, UniCapsColl}; use crate::drivers::vsock::{EventQueue, RxQueue, TxQueue, VirtioVsockDriver, VsockDevCfg}; -/// Virtio's socket device configuration structure. -/// See specification v1.1. - 5.11.4 -/// -#[derive(Debug, Copy, Clone)] -#[repr(C)] -pub(crate) struct VsockDevCfgRaw { - /// The guest_cid field contains the guest’s context ID, which uniquely identifies the device - /// for its lifetime. The upper 32 bits of the CID are reserved and zeroed. - pub guest_cid: u64, -} - impl VirtioVsockDriver { fn map_cfg(cap: &PciCap) -> Option { - let dev_cfg = pci::map_dev_cfg::(cap)?; + let dev_cfg = pci::map_dev_cfg::(cap)?; + + let dev_cfg = VolatileRef::from_ref(dev_cfg); Some(VsockDevCfg { raw: dev_cfg, @@ -82,10 +75,8 @@ impl VirtioVsockDriver { match drv.init_dev() { Ok(()) => { - info!( - "Socket device with cid {:x}, has been initialized by driver!", - drv.dev_cfg.raw.guest_cid - ); + let cid = drv.get_cid(); + info!("Socket device with cid {cid:x}, has been initialized by driver!"); Ok(drv) }