From 86e404b40f5ae6b56a871f7288e007b3c8351906 Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Thu, 19 Aug 2021 15:36:25 -0700 Subject: [PATCH 01/15] Added Virtio Backend Domain --- Makefile | 1 + domains/Cargo.lock | 16 +++++++++ domains/Cargo.toml | 1 + domains/sys/driver/virtio_backend/Cargo.toml | 22 ++++++++++++ domains/sys/driver/virtio_backend/src/main.rs | 35 +++++++++++++++++++ domains/sys/init/src/main.rs | 18 +++++++--- domains/usr/proxy/src/main.rs | 2 ++ interface/src/domain_create.rs | 6 ++++ interface/src/proxy.rs | 8 ++++- 9 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 domains/sys/driver/virtio_backend/Cargo.toml create mode 100644 domains/sys/driver/virtio_backend/src/main.rs diff --git a/Makefile b/Makefile index d6f77a17..31b5a423 100644 --- a/Makefile +++ b/Makefile @@ -72,6 +72,7 @@ domain_list := $(addprefix domains/build/, \ ixgbe \ virtio_net \ virtio_block \ + virtio_backend \ nvme \ tpm \ bdev_shadow \ diff --git a/domains/Cargo.lock b/domains/Cargo.lock index ad641d87..f1b6be7e 100644 --- a/domains/Cargo.lock +++ b/domains/Cargo.lock @@ -997,6 +997,22 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +[[package]] +name = "virtio_backend" +version = "0.1.0" +dependencies = [ + "console", + "interface", + "libsyscalls", + "libtime", + "malloc", + "pci_driver", + "platform", + "protocol", + "spin 0.5.3", + "syscalls", +] + [[package]] name = "virtio_block" version = "0.1.0" diff --git a/domains/Cargo.toml b/domains/Cargo.toml index a197b8fc..5080e003 100644 --- a/domains/Cargo.toml +++ b/domains/Cargo.toml @@ -10,6 +10,7 @@ members = [ "sys/driver/tpm", "sys/driver/virtio_net", "sys/driver/virtio_block", + "sys/driver/virtio_backend", "sys/init", "usr/proxy", "usr/shadow/bdev", diff --git a/domains/sys/driver/virtio_backend/Cargo.toml b/domains/sys/driver/virtio_backend/Cargo.toml new file mode 100644 index 00000000..3c413dce --- /dev/null +++ b/domains/sys/driver/virtio_backend/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "virtio_backend" +version = "0.1.0" +authors = ["RedLeaf Team"] +edition = "2018" + +[dependencies] +libsyscalls = { path = "../../../../lib/core/libsyscalls" } +libtime = { path = "../../../../lib/core/libtime" } +console = { path = "../../../../lib/core/console" } +malloc = { path = "../../../../lib/core/malloc" } +spin = { path = "../../../../lib/core/spin-rs" } + +# Interfaces +syscalls = { path = "../../../../lib/core/interfaces/syscalls" } +pci_driver = { path = "../../../../lib/core/interfaces/dev/pci/pci_driver" } +protocol = { path = "../../../../lib/core/interfaces/protocol" } +platform = { path = "../../../../lib/core/interfaces/platform" } +interface = { path = "../../../../interface/generated" } + +[features] +default = [] \ No newline at end of file diff --git a/domains/sys/driver/virtio_backend/src/main.rs b/domains/sys/driver/virtio_backend/src/main.rs new file mode 100644 index 00000000..80aab049 --- /dev/null +++ b/domains/sys/driver/virtio_backend/src/main.rs @@ -0,0 +1,35 @@ +#![no_std] +#![no_main] +#![feature( + box_syntax, + const_fn, + const_raw_ptr_to_usize_cast, + const_in_array_repeat_expressions, + untagged_unions, + maybe_uninit_extra +)] + +extern crate alloc; +extern crate malloc; + +use alloc::boxed::Box; +use console::println; +use core::panic::PanicInfo; +use libsyscalls::syscalls::sys_backtrace; +use syscalls::{Heap, Syscall}; + +#[no_mangle] +pub fn trusted_entry(s: Box, heap: Box) { + libsyscalls::syscalls::init(s); + interface::rref::init(heap, libsyscalls::syscalls::sys_get_current_domain_id()); + + println!("Virtio Backend!"); +} + +// This function is called on panic. +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + println!("{:?}", info); + sys_backtrace(); + loop {} +} diff --git a/domains/sys/init/src/main.rs b/domains/sys/init/src/main.rs index 09db916a..9b5128c1 100644 --- a/domains/sys/init/src/main.rs +++ b/domains/sys/init/src/main.rs @@ -109,6 +109,7 @@ pub fn trusted_entry( create_ixgbe: Arc, create_virtio_net: Arc, create_virtio_block: Arc, + create_virtio_backend: Arc, create_net_shadow: Arc, create_nvme_shadow: Arc, create_nvme: Arc, @@ -193,6 +194,7 @@ pub fn trusted_entry( create_ixgbe, create_virtio_net, create_virtio_block, + create_virtio_backend, create_nvme, create_net_shadow, create_nvme_shadow, @@ -238,8 +240,19 @@ pub fn trusted_entry( let (_, net) = proxy .as_domain_create_CreateVirtioNet() .create_domain_virtio_net(pci.pci_clone().unwrap()); + + #[cfg(feature = "virtio_block")] + let (_, virtio_block) = proxy + .as_domain_create_CreateVirtioBlock() + .create_domain_virtio_block(pci.pci_clone().unwrap()); + + let (_) = proxy + .as_domain_create_CreateVirtioBackend() + .create_domain_virtio_backend(); + #[cfg(all(not(feature = "shadow"), not(feature = "virtnet")))] let (_, net) = proxy.as_create_ixgbe().create_domain_ixgbe(pci.pci_clone()); + #[cfg(all(feature = "shadow", not(feature = "virtio_net")))] let (_, net) = proxy .as_create_net_shadow() @@ -289,11 +302,6 @@ pub fn trusted_entry( #[cfg(feature = "benchnet")] let _ = proxy.as_create_benchnet().create_domain_benchnet(net); - #[cfg(feature = "virtio_block")] - let (_, virtio_block) = proxy - .as_domain_create_CreateVirtioBlock() - .create_domain_virtio_block(pci.pci_clone().unwrap()); - #[cfg(feature = "benchnvme")] let _ = proxy .as_domain_create_CreateBenchnvme() diff --git a/domains/usr/proxy/src/main.rs b/domains/usr/proxy/src/main.rs index 1fa96d33..7d4fb4d7 100644 --- a/domains/usr/proxy/src/main.rs +++ b/domains/usr/proxy/src/main.rs @@ -25,6 +25,7 @@ pub fn trusted_entry( create_ixgbe: alloc::sync::Arc, create_virtio_net: alloc::sync::Arc, create_virtio_block: Arc, + create_virtio_backend: Arc, create_nvme: alloc::sync::Arc, create_net_shadow: alloc::sync::Arc, create_nvme_shadow: alloc::sync::Arc, @@ -49,6 +50,7 @@ pub fn trusted_entry( create_ixgbe, create_virtio_net, create_virtio_block, + create_virtio_backend, create_net_shadow, create_nvme_shadow, create_nvme, diff --git a/interface/src/domain_create.rs b/interface/src/domain_create.rs index 333bfa5a..f5889389 100644 --- a/interface/src/domain_create.rs +++ b/interface/src/domain_create.rs @@ -24,6 +24,7 @@ pub trait CreateProxy { create_ixgbe: Arc, create_virtio_net: Arc, create_virtio_block: Arc, + create_virtio_backend: Arc, create_nvme: Arc, create_net_shadow: Arc, create_nvme_shadow: Arc, @@ -86,6 +87,11 @@ pub trait CreateVirtioBlock: Send + Sync { -> (Box, Box); } +#[domain_create(path = "virtio_backend")] +pub trait CreateVirtioBackend: Send + Sync { + fn create_domain_virtio_backend(&self) -> (Box, ()); +} + #[domain_create(path = "net_shadow")] pub trait CreateNetShadow: Send + Sync { fn create_domain_net_shadow( diff --git a/interface/src/proxy.rs b/interface/src/proxy.rs index 8913e16f..41e7b14c 100644 --- a/interface/src/proxy.rs +++ b/interface/src/proxy.rs @@ -3,7 +3,7 @@ use crate::domain_create::{ CreateAHCI, CreateBDevShadow, CreateBenchnet, CreateBenchnvme, CreateDomC, CreateDomD, CreateIxgbe, CreateMemBDev, CreateNetShadow, CreateNvme, CreateNvmeShadow, CreatePCI, CreateRv6, CreateRv6FS, CreateRv6Net, CreateRv6NetShadow, CreateRv6Usr, CreateShadow, - CreateVirtioBlock, CreateVirtioNet, + CreateVirtioBackend, CreateVirtioBlock, CreateVirtioNet, }; use alloc::boxed::Box; use alloc::sync::Arc; @@ -22,12 +22,18 @@ pub trait Proxy: + CreateDomC + CreateDomD + CreateShadow + + CreateVirtioNet + + CreateVirtioBlock + + CreateVirtioBackend { // necessary because rust doesn't support trait object upcasting fn as_domain_create_CreateVirtioNet(&self) -> Arc; fn as_domain_create_CreateVirtioBlock( &self, ) -> Arc; + fn as_domain_create_CreateVirtioBackend( + &self, + ) -> Arc; fn as_domain_create_CreateIxgbe(&self) -> Arc; fn as_domain_create_CreateDomD(&self) -> Arc; fn as_domain_create_CreateMemBDev(&self) -> Arc; From ac3042c5fa9e1141fcc9cb4414077755736cce32 Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Sat, 21 Aug 2021 17:30:41 -0700 Subject: [PATCH 02/15] Setup thread stuff --- domains/Cargo.lock | 2 + domains/sys/driver/virtio_backend/Cargo.toml | 3 + domains/sys/driver/virtio_backend/src/main.rs | 89 ++++++++++++++++++- lib/devices/virtio_net/src/lib.rs | 7 +- 4 files changed, 98 insertions(+), 3 deletions(-) diff --git a/domains/Cargo.lock b/domains/Cargo.lock index f1b6be7e..222d81bc 100644 --- a/domains/Cargo.lock +++ b/domains/Cargo.lock @@ -1011,6 +1011,8 @@ dependencies = [ "protocol", "spin 0.5.3", "syscalls", + "virtio_device", + "virtio_network_device", ] [[package]] diff --git a/domains/sys/driver/virtio_backend/Cargo.toml b/domains/sys/driver/virtio_backend/Cargo.toml index 3c413dce..eb938d90 100644 --- a/domains/sys/driver/virtio_backend/Cargo.toml +++ b/domains/sys/driver/virtio_backend/Cargo.toml @@ -18,5 +18,8 @@ protocol = { path = "../../../../lib/core/interfaces/protocol" } platform = { path = "../../../../lib/core/interfaces/platform" } interface = { path = "../../../../interface/generated" } +virtio_device = { path = "../../../../lib/devices/virtio" } +virtio_network_device = { path = "../../../../lib/devices/virtio_net" } + [features] default = [] \ No newline at end of file diff --git a/domains/sys/driver/virtio_backend/src/main.rs b/domains/sys/driver/virtio_backend/src/main.rs index 80aab049..a810fad6 100644 --- a/domains/sys/driver/virtio_backend/src/main.rs +++ b/domains/sys/driver/virtio_backend/src/main.rs @@ -12,11 +12,64 @@ extern crate alloc; extern crate malloc; -use alloc::boxed::Box; +use alloc::{boxed::Box, vec, vec::Vec}; use console::println; use core::panic::PanicInfo; -use libsyscalls::syscalls::sys_backtrace; +use libsyscalls::syscalls::{sys_backtrace, sys_create_thread, sys_yield}; use syscalls::{Heap, Syscall}; +use virtio_device::VirtioPciCommonConfig; +use virtio_network_device::VirtioNetInner; + +#[derive(Debug)] +struct VirtioBackendQueue { + queue_index: u16, + queue_size: u16, + queue_enable: bool, + queue_descriptor: u64, + queue_driver: u64, + queue_device: u64, +} + +const MAX_SUPPORTED_QUEUES: u16 = 3; + +static mut VIRTIO_DEVICE_CONFIG: VirtioPciCommonConfig = VirtioPciCommonConfig { + /* About the whole device. */ + device_feature_select: 0, /* read-write */ + device_feature: 0, /* read-only for driver */ + driver_feature_select: 0, /* read-write */ + driver_feature: 0, /* read-write */ + msix_config: 0, /* read-write */ + num_queues: MAX_SUPPORTED_QUEUES, /* read-only for driver */ + device_status: 0, /* read-write */ + config_generation: 0, /* read-only for driver */ + + /* About a specific virtqueue. */ + queue_select: 0, /* read-write */ + + /// Maximum number of items in Descriptor Queue + queue_size: 256, /* read-write */ + queue_msix_vector: 0, /* read-write */ + queue_enable: 0, /* read-write */ + queue_notify_off: 0, /* read-only for driver */ + queue_desc: 0, /* read-write */ + + /// Available Ring + queue_driver: 0, /* read-write */ + + /// Used Ring + queue_device: 0, /* read-write */ +}; + +extern "C" fn virtio_frontend() { + unsafe { + let mut VirtioInner = + VirtioNetInner::new(&VIRTIO_DEVICE_CONFIG as *const VirtioPciCommonConfig as usize); + + sys_yield(); + + VirtioInner.init(); + } +} #[no_mangle] pub fn trusted_entry(s: Box, heap: Box) { @@ -24,6 +77,38 @@ pub fn trusted_entry(s: Box, heap: Box> = vec![None, None, None]; + + loop { + unsafe { + println!("{:#?}", VIRTIO_DEVICE_CONFIG); + + // Update the backend's info on the queues + if VIRTIO_DEVICE_CONFIG.queue_enable == 1 { + if VIRTIO_DEVICE_CONFIG.queue_select >= MAX_SUPPORTED_QUEUES { + panic!("Virtio Backend Supports at most {} queues but the device has a queue at index {}", MAX_SUPPORTED_QUEUES, VIRTIO_DEVICE_CONFIG.queue_select); + } + + // Update the queue information + let queue = VirtioBackendQueue { + queue_index: VIRTIO_DEVICE_CONFIG.queue_select, + queue_enable: true, + queue_size: VIRTIO_DEVICE_CONFIG.queue_size, + queue_descriptor: VIRTIO_DEVICE_CONFIG.queue_desc, + queue_device: VIRTIO_DEVICE_CONFIG.queue_device, + queue_driver: VIRTIO_DEVICE_CONFIG.queue_driver, + }; + + backend_queues[VIRTIO_DEVICE_CONFIG.queue_select as usize] = Some(queue); + } + + println!("{:#?}", &backend_queues); + } + sys_yield(); + } } // This function is called on panic. diff --git a/lib/devices/virtio_net/src/lib.rs b/lib/devices/virtio_net/src/lib.rs index 5cd9c14a..0a5d99f6 100644 --- a/lib/devices/virtio_net/src/lib.rs +++ b/lib/devices/virtio_net/src/lib.rs @@ -89,7 +89,7 @@ pub struct VirtioNetInner { impl VirtioNetInner { /// Returns an initialized VirtioNet from a base address. - unsafe fn new(mmio_base: usize) -> Self { + pub unsafe fn new(mmio_base: usize) -> Self { Self { mmio: Mmio::new(mmio_base), @@ -172,6 +172,11 @@ impl VirtioNetInner { // Setup Virtual Queues self.initialize_virtual_queue(0, &(self.virtual_queues.as_ref().unwrap().receive_queue)); + + println!("Virtio Net Should Yield here!"); + self.print_device_config(); + libsyscalls::syscalls::sys_yield(); + self.initialize_virtual_queue(1, &(self.virtual_queues.as_ref().unwrap().transmit_queue)); // Tell the Device we're all done, even though we aren't From 7bf3a7f173057d4155a11051e5faeea1e777fee6 Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Sun, 22 Aug 2021 20:49:47 -0700 Subject: [PATCH 03/15] Attempting new method --- domains/Cargo.lock | 1 - domains/sys/driver/virtio_backend/Cargo.toml | 1 - domains/sys/driver/virtio_backend/src/defs.rs | 27 + domains/sys/driver/virtio_backend/src/main.rs | 189 ++++--- domains/sys/driver/virtio_backend/src/pci.rs | 56 +++ .../driver/virtio_backend/src/virtio_net.rs | 473 ++++++++++++++++++ lib/devices/virtio/src/defs.rs | 15 +- lib/devices/virtio_net/src/lib.rs | 6 +- 8 files changed, 689 insertions(+), 79 deletions(-) create mode 100644 domains/sys/driver/virtio_backend/src/defs.rs create mode 100644 domains/sys/driver/virtio_backend/src/pci.rs create mode 100644 domains/sys/driver/virtio_backend/src/virtio_net.rs diff --git a/domains/Cargo.lock b/domains/Cargo.lock index 222d81bc..200e44da 100644 --- a/domains/Cargo.lock +++ b/domains/Cargo.lock @@ -1012,7 +1012,6 @@ dependencies = [ "spin 0.5.3", "syscalls", "virtio_device", - "virtio_network_device", ] [[package]] diff --git a/domains/sys/driver/virtio_backend/Cargo.toml b/domains/sys/driver/virtio_backend/Cargo.toml index eb938d90..271f0a29 100644 --- a/domains/sys/driver/virtio_backend/Cargo.toml +++ b/domains/sys/driver/virtio_backend/Cargo.toml @@ -19,7 +19,6 @@ platform = { path = "../../../../lib/core/interfaces/platform" } interface = { path = "../../../../interface/generated" } virtio_device = { path = "../../../../lib/devices/virtio" } -virtio_network_device = { path = "../../../../lib/devices/virtio_net" } [features] default = [] \ No newline at end of file diff --git a/domains/sys/driver/virtio_backend/src/defs.rs b/domains/sys/driver/virtio_backend/src/defs.rs new file mode 100644 index 00000000..c09dfc9d --- /dev/null +++ b/domains/sys/driver/virtio_backend/src/defs.rs @@ -0,0 +1,27 @@ +use virtio_device::defs::VirtQueue; + +pub const MAX_SUPPORTED_QUEUES: u16 = 3; + +#[derive(Debug)] +pub struct VirtioBackendQueue { + pub queue_index: u16, + pub queue_size: u16, + pub queue_enable: bool, + pub queue_descriptor: u64, + pub queue_driver: u64, + pub queue_device: u64, + + /// The next idx to process for the driver queue + pub driver_idx: u16, + + /// The next idx to process for the device queue + pub device_idx: u16, +} + +impl VirtioBackendQueue { + pub fn get_driver_queue(&mut self) -> &mut VirtQueue { + unsafe { + return &mut *(self.queue_driver as *mut VirtQueue); + } + } +} diff --git a/domains/sys/driver/virtio_backend/src/main.rs b/domains/sys/driver/virtio_backend/src/main.rs index a810fad6..c9fc4e66 100644 --- a/domains/sys/driver/virtio_backend/src/main.rs +++ b/domains/sys/driver/virtio_backend/src/main.rs @@ -12,105 +12,148 @@ extern crate alloc; extern crate malloc; -use alloc::{boxed::Box, vec, vec::Vec}; +mod defs; +mod virtio_net; + +use crate::{ + defs::{VirtioBackendQueue, MAX_SUPPORTED_QUEUES}, + virtio_net::VirtioNetInner, +}; +use alloc::{boxed::Box, sync::Arc, vec, vec::Vec}; use console::println; -use core::panic::PanicInfo; +use core::{ + borrow::{Borrow, BorrowMut}, + panic::PanicInfo, +}; use libsyscalls::syscalls::{sys_backtrace, sys_create_thread, sys_yield}; +use spin::{Mutex, MutexGuard, Once}; use syscalls::{Heap, Syscall}; use virtio_device::VirtioPciCommonConfig; -use virtio_network_device::VirtioNetInner; - -#[derive(Debug)] -struct VirtioBackendQueue { - queue_index: u16, - queue_size: u16, - queue_enable: bool, - queue_descriptor: u64, - queue_driver: u64, - queue_device: u64, +struct VirtioBackendInner { + device_config: VirtioPciCommonConfig, + backend_queues: Vec>, } -const MAX_SUPPORTED_QUEUES: u16 = 3; - -static mut VIRTIO_DEVICE_CONFIG: VirtioPciCommonConfig = VirtioPciCommonConfig { - /* About the whole device. */ - device_feature_select: 0, /* read-write */ - device_feature: 0, /* read-only for driver */ - driver_feature_select: 0, /* read-write */ - driver_feature: 0, /* read-write */ - msix_config: 0, /* read-write */ - num_queues: MAX_SUPPORTED_QUEUES, /* read-only for driver */ - device_status: 0, /* read-write */ - config_generation: 0, /* read-only for driver */ - - /* About a specific virtqueue. */ - queue_select: 0, /* read-write */ - - /// Maximum number of items in Descriptor Queue - queue_size: 256, /* read-write */ - queue_msix_vector: 0, /* read-write */ - queue_enable: 0, /* read-write */ - queue_notify_off: 0, /* read-only for driver */ - queue_desc: 0, /* read-write */ - - /// Available Ring - queue_driver: 0, /* read-write */ - - /// Used Ring - queue_device: 0, /* read-write */ -}; +struct VirtioBackend(Once>>); -extern "C" fn virtio_frontend() { - unsafe { - let mut VirtioInner = - VirtioNetInner::new(&VIRTIO_DEVICE_CONFIG as *const VirtioPciCommonConfig as usize); +impl VirtioBackend { + pub const fn new() -> Self { + VirtioBackend(Once::new()) + } - sys_yield(); + pub fn init(&mut self) { + self.0.call_once(|| { + Arc::new(Mutex::new(VirtioBackendInner { + device_config: VirtioPciCommonConfig { + device_feature_select: 0, + device_feature: 0, + driver_feature_select: 0, + driver_feature: 0, + msix_config: 0, + num_queues: MAX_SUPPORTED_QUEUES, + device_status: 0, + config_generation: 0, + queue_select: 0, + queue_size: 256, + queue_msix_vector: 0, + queue_enable: 0, + queue_notify_off: 0, + queue_desc: 0, + queue_driver: 0, + queue_device: 0, + }, + backend_queues: vec![None, None, None], + })) + }); + } - VirtioInner.init(); + pub fn lock(&mut self) -> MutexGuard { + self.0.wait().unwrap().lock() } } -#[no_mangle] -pub fn trusted_entry(s: Box, heap: Box) { - libsyscalls::syscalls::init(s); - interface::rref::init(heap, libsyscalls::syscalls::sys_get_current_domain_id()); - - println!("Virtio Backend!"); - - let virtio_frontend_thread = sys_create_thread("virtio_frontend", virtio_frontend); - - let mut backend_queues: Vec> = vec![None, None, None]; - - loop { - unsafe { - println!("{:#?}", VIRTIO_DEVICE_CONFIG); +static mut VIRTIO_BACKEND: VirtioBackend = VirtioBackend::new(); - // Update the backend's info on the queues - if VIRTIO_DEVICE_CONFIG.queue_enable == 1 { - if VIRTIO_DEVICE_CONFIG.queue_select >= MAX_SUPPORTED_QUEUES { - panic!("Virtio Backend Supports at most {} queues but the device has a queue at index {}", MAX_SUPPORTED_QUEUES, VIRTIO_DEVICE_CONFIG.queue_select); - } +/// Call this function anytime the frontend modifies device config and backend needs to update +pub fn virtio_device_config_modified() { + let mut backend = unsafe { VIRTIO_BACKEND.borrow_mut().lock() }; + unsafe { + // Update the backend's info on the queues + if backend.device_config.queue_enable == 1 { + if backend.device_config.queue_select >= MAX_SUPPORTED_QUEUES { + panic!("Virtio Backend Supports at most {} queues but the device has a queue at index {}", + MAX_SUPPORTED_QUEUES, + backend.device_config.queue_select); + } else { // Update the queue information let queue = VirtioBackendQueue { - queue_index: VIRTIO_DEVICE_CONFIG.queue_select, + queue_index: backend.device_config.queue_select, queue_enable: true, - queue_size: VIRTIO_DEVICE_CONFIG.queue_size, - queue_descriptor: VIRTIO_DEVICE_CONFIG.queue_desc, - queue_device: VIRTIO_DEVICE_CONFIG.queue_device, - queue_driver: VIRTIO_DEVICE_CONFIG.queue_driver, + queue_size: backend.device_config.queue_size, + queue_descriptor: backend.device_config.queue_desc, + queue_device: backend.device_config.queue_device, + queue_driver: backend.device_config.queue_driver, + + device_idx: 0, + driver_idx: 0, }; - backend_queues[VIRTIO_DEVICE_CONFIG.queue_select as usize] = Some(queue); + let index = queue.queue_index; + backend.backend_queues[index as usize] = Some(queue); } + } + + println!( + "virtio_device_config_modified {:#?}", + &backend.backend_queues + ); + } +} + +extern "C" fn virtio_frontend() { + let backend = unsafe { VIRTIO_BACKEND.borrow_mut() }; + + unsafe { + let mut VirtioInner = VirtioNetInner::new( + &backend.lock().device_config as *const VirtioPciCommonConfig as usize, + ); + + VirtioInner.init(); + } +} + +fn virtio_backend() { + let backend = unsafe { VIRTIO_BACKEND.borrow_mut() }; + + loop { + println!("{:#?}", backend.lock().device_config); + println!("{:#?}", backend.lock().backend_queues); - println!("{:#?}", &backend_queues); + for q in &mut backend.lock().backend_queues { + if let Some(queue) = q.as_mut() { + println!("Driver Queue: {:#?}", queue.get_driver_queue()); + } } + + println!("Virtio Backend Yield"); sys_yield(); } } +#[no_mangle] +pub fn trusted_entry(s: Box, heap: Box) { + libsyscalls::syscalls::init(s); + interface::rref::init(heap, libsyscalls::syscalls::sys_get_current_domain_id()); + + unsafe { + VIRTIO_BACKEND.init(); + } + + sys_create_thread("virtio_frontend", virtio_frontend); + virtio_backend(); +} + // This function is called on panic. #[panic_handler] fn panic(info: &PanicInfo) -> ! { diff --git a/domains/sys/driver/virtio_backend/src/pci.rs b/domains/sys/driver/virtio_backend/src/pci.rs new file mode 100644 index 00000000..2d35c0a6 --- /dev/null +++ b/domains/sys/driver/virtio_backend/src/pci.rs @@ -0,0 +1,56 @@ +use console::println; +use pci_driver::DeviceBarRegions; + +use crate::VirtioNetInner; + +use alloc::boxed::Box; +use interface::net::Net; + +const VIRTIO_PCI_VID: u16 = 0x1af4; +const VIRTIO_PCI_DID: u16 = 0x1000; + +pub struct PciFactory { + mmio_base: Option, +} + +impl pci_driver::PciDriver for PciFactory { + fn probe(&mut self, bar_region: DeviceBarRegions) { + println!("VirtioNet PCI probe called"); + match bar_region { + DeviceBarRegions::Virtio(bar) => unsafe { + self.mmio_base = Some(bar.get_base() as usize); + }, + ty => { + println!("VirtioNet PCI probed with unsupported device {:?}", ty); + } + } + } + + /// Returns the Vendor ID for a VIRTIO Network Device + fn get_vid(&self) -> u16 { + VIRTIO_PCI_VID + } + + /// Returns the Device ID for a VIRTIO Network Device + fn get_did(&self) -> u16 { + // FIXME: Another possibility is the Transitional Device ID 0x1000 + VIRTIO_PCI_DID + } + + fn get_driver_type(&self) -> pci_driver::PciDrivers { + pci_driver::PciDrivers::VirtioDriver + } +} + +impl PciFactory { + pub fn new() -> Self { + Self { mmio_base: None } + } + + pub fn to_device(self) -> Option { + self.mmio_base.map(|base| { + let dev = unsafe { VirtioNetInner::new(base) }; + dev + }) + } +} diff --git a/domains/sys/driver/virtio_backend/src/virtio_net.rs b/domains/sys/driver/virtio_backend/src/virtio_net.rs new file mode 100644 index 00000000..ea6b3a84 --- /dev/null +++ b/domains/sys/driver/virtio_backend/src/virtio_net.rs @@ -0,0 +1,473 @@ +#![no_std] +#![no_main] +#![feature( + box_syntax, + const_fn, + const_raw_ptr_to_usize_cast, + const_in_array_repeat_expressions, + untagged_unions, + maybe_uninit_extra +)] + +extern crate alloc; + +use core::usize; + +use alloc::alloc::{alloc, Layout}; +use alloc::sync::Arc; +use alloc::vec; +use alloc::vec::Vec; +use console::println; +use interface::rref::{RRef, RRefDeque}; +use spin::Mutex; +use virtio_device::defs::{ + VirtQueue, VirtqAvailable, VirtqAvailablePacked, VirtqDescriptor, VirtqUsed, VirtqUsedElement, + VirtqUsedPacked, +}; +use virtio_device::{Mmio, VirtioDeviceStatus}; + +use crate::virtio_device_config_modified; + +#[repr(C, packed)] +pub struct VirtioNetworkDeviceConfig { + mac: [u8; 6], + status: u16, + // Not available without negotiating features VIRTIO_NET_F_MQ and VIRTIO_NET_F_MTU + // max_virtqueue_pairs: u16, + // mtu: u16, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct VirtioNetworkHeader { + pub flags: u8, + pub gso_type: u8, + pub header_length: u16, + pub gso_size: u16, + pub csum_start: u16, + pub csum_offset: u16, + // pub num_buffers: u16, +} + +struct VirtualQueues { + receive_queue: VirtQueue, + transmit_queue: VirtQueue, +} + +type NetworkPacketBuffer = [u8; 1514]; + +pub struct VirtioNetInner { + mmio: Mmio, + virtual_queues: Option, // None until init() is called + + /// This is the size of the queues used by the device, it is read during init(). + /// It would be less annoying to use if it were usize but it truly is a u16 value. + queue_size: u16, + + /// This tracks the maximum number of buffers or descriptor chains we can simultaneiously have. + /// For the network driver, each network packet requires two descriptors so this will be + /// queue_size / 2. + buffer_count: usize, + + /// Dummy VirtioNetHeaders. + /// The driver doesn't actually use these but they are required by the spec + virtio_network_headers: Vec, + + /// Tracks which descriptors on the queue are free + rx_free_descriptors: Vec, + /// Tracks which descriptors on the queue are free + tx_free_descriptors: Vec, + + /// The last index (of the used ring) that was checked by the driver + rx_last_idx: u16, + /// The last index (of the used ring) that was checked by the driver + tx_last_idx: u16, + + rx_buffers: Vec>>, + tx_buffers: Vec>>, +} + +impl VirtioNetInner { + /// Returns an initialized VirtioNet from a base address. + pub unsafe fn new(mmio_base: usize) -> Self { + Self { + mmio: Mmio::new(mmio_base), + + queue_size: 0, // We will update this (and the vecs) in init() + buffer_count: 0, + + virtual_queues: None, + + virtio_network_headers: vec![], + + rx_free_descriptors: vec![], + tx_free_descriptors: vec![], + + rx_buffers: vec![], + tx_buffers: vec![], + + rx_last_idx: 0, + tx_last_idx: 0, + } + } + + pub fn init(&mut self) { + println!("Initializing Virtio Network Device"); + + // VIRTIO DEVICE INIT + // https://docs.oasis-open.org/virtio/virtio/v1.1/cs01/virtio-v1.1-cs01.html#x1-920001 + // + // Reset the device. + // Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. + // Set the DRIVER status bit: the guest OS knows how to drive the device. + // Read device feature bits, and write the subset of feature bits understood by the OS and driver to the device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration fields to check that it can support the device before accepting it. + // Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. + // Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. + // Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup, reading and possibly writing the device’s virtio configuration space, and population of virtqueues. + // Set the DRIVER_OK status bit. At this point the device is “live”. + + // Reset the device + // Failing to do this DOES cause errors, don't ask how I know *sigh* + self.mmio.accessor.write_device_status(0); + Mmio::memory_fence(); + + // Acknowledge Device + unsafe { + self.mmio + .update_device_status(VirtioDeviceStatus::Acknowledge); + self.mmio.update_device_status(VirtioDeviceStatus::Driver); // But do we really know how to drive the device? + } + + self.negotiate_features(); + + // Tell the Device that feature Negotiation is complete + unsafe { + self.mmio + .update_device_status(VirtioDeviceStatus::FeaturesOk); + } + + // Check that Features OK Bit is still set! + // self.print_device_status(); + if (self.mmio.accessor.read_device_status() & VirtioDeviceStatus::FeaturesOk.value()) == 0 { + panic!("Failed to negotiate Virtio Net features!"); + } + + // Read the queue size + // This value is that largest possible queue size so we will use it to initialize all of our vectors + let queue_size = self.mmio.accessor.read_queue_size(); + if queue_size == 0 { + panic!("ERROR: VIRTIO NET: BAD QUEUE SIZE!"); + } + + self.queue_size = queue_size; + self.buffer_count = (self.queue_size / 2) as usize; // Each buffer requires two descriptors + + unsafe { + self.setup_virtual_queues(); + } + + self.initialize_vectors(); + + // Setup Virtual Queues + self.initialize_virtual_queue(0, &(self.virtual_queues.as_ref().unwrap().receive_queue)); + + // println!("Virtio Net Should Yield here!"); + // self.print_device_config(); + // libsyscalls::syscalls::sys_yield(); + + virtio_device_config_modified(); + + self.initialize_virtual_queue(1, &(self.virtual_queues.as_ref().unwrap().transmit_queue)); + + virtio_device_config_modified(); + + // Tell the Device we're all done, even though we aren't + unsafe { self.mmio.update_device_status(VirtioDeviceStatus::DriverOk) }; + + // self.print_device_status(); + + // self.mmio.accessor.write_queue_select(0); + // self.print_device_config(); + // self.mmio.accessor.write_queue_select(1); + // self.print_device_config(); + + println!("VIRTIO NET READY!"); + } + + /// Negotiates Virtio Driver Features + fn negotiate_features(&mut self) { + let mut driver_features: u32 = 0; + driver_features |= 1 << 5; // Enable Device MAC Address + driver_features |= 1 << 16; // Enable Device Status + + self.mmio.accessor.write_driver_feature(driver_features); // Should be &'d with device_features + } + + pub fn print_device_config(&mut self) { + let mut cfg = unsafe { self.mmio.read_common_config() }; + println!("{:#?}", cfg); + } + + pub fn print_device_status(&mut self) { + let device_status = self.mmio.accessor.read_device_status(); + println!("Device Status Bits: {:b}", device_status); + } + + /// Initializes all the vectors using the set buffer_count + fn initialize_vectors(&mut self) { + self.virtio_network_headers = vec![ + VirtioNetworkHeader { + csum_offset: 0, + csum_start: 0, + flags: 0, + gso_size: 0, + gso_type: 0, + header_length: 0, + }; + self.buffer_count + ]; + + self.rx_free_descriptors = vec![true; self.buffer_count]; + self.tx_free_descriptors = vec![true; self.buffer_count]; + + self.rx_buffers = Vec::with_capacity(self.buffer_count); + self.rx_buffers.resize_with(self.buffer_count, || None); + self.tx_buffers = Vec::with_capacity(self.buffer_count); + self.tx_buffers.resize_with(self.buffer_count, || None); + } + + unsafe fn setup_virtual_queues(&mut self) { + self.virtual_queues = Some(VirtualQueues { + receive_queue: VirtQueue { + descriptors: vec![VirtqDescriptor::default(); self.queue_size as usize], + available: VirtqAvailable::new(self.queue_size), + used: VirtqUsed::new(self.queue_size), + }, + transmit_queue: VirtQueue { + descriptors: vec![VirtqDescriptor::default(); self.queue_size as usize], + available: VirtqAvailable::new(self.queue_size), + used: VirtqUsed::new(self.queue_size), + }, + }); + } + + /// Receive Queues must be 2*N and Transmit Queues must be 2*N + 1 + /// For example, Receive Queue must be 0 and Transmit Queue must be 1 + fn initialize_virtual_queue(&self, queue_index: u16, virt_queue: &VirtQueue) { + self.mmio.accessor.write_queue_select(queue_index); + + self.mmio + .accessor + .write_queue_desc(virt_queue.descriptors.as_ptr() as u64); + self.mmio.accessor.write_queue_driver( + (virt_queue.available.data.as_ref() as *const VirtqAvailablePacked) as u64, + ); + self.mmio + .accessor + .write_queue_device((virt_queue.used.data.as_ref() as *const VirtqUsedPacked) as u64); + self.mmio.accessor.write_queue_enable(1); + } + + /// Returns a free descriptor chain index + /// For Virtio Net, the VirtioNetworkHeader is placed at i and the Packet Buffer will be placed at i + self.buffer_count + fn get_free_idx(free_buffers: &mut Vec) -> Result { + for i in 0..free_buffers.len() { + if free_buffers[i] { + free_buffers[i] = false; + return Ok(i); + } + } + + return Err(()); + } + + #[inline] + fn get_addr(obj: &T) -> u64 { + (obj as *const T) as u64 + } + + /// If the buffer can't be added, it is returned in the Err() + fn add_rx_buffer( + &mut self, + buffer: RRef, + ) -> Result<(), RRef> { + let rx_q = &mut self.virtual_queues.as_mut().unwrap().receive_queue; + + if let Ok(header_idx) = Self::get_free_idx(&mut self.rx_free_descriptors) { + let buffer_idx = header_idx + self.buffer_count; + let buffer_addr = buffer.as_ptr() as u64; + + // Store it so it isn't dropped + self.rx_buffers[header_idx] = Some(buffer); + + // One descriptor points at the network header, chain this with a descriptor to the buffer + // Header + rx_q.descriptors[header_idx] = VirtqDescriptor { + addr: Self::get_addr(&self.virtio_network_headers[header_idx]), + len: core::mem::size_of::() as u32, // 10 bytes + // 1 is NEXT FLAG + // 2 is WRITABLE FLAG + flags: 1 | 2, + next: buffer_idx as u16, + }; + // Actual Buffer + rx_q.descriptors[buffer_idx] = VirtqDescriptor { + addr: buffer_addr, + len: 1514, + flags: 2, + next: 0, + }; + + // Mark the buffer as usable + *rx_q + .available + .ring(rx_q.available.data.idx % self.queue_size) = header_idx as u16; + rx_q.available.data.idx = rx_q.available.data.idx.wrapping_add(1); // We only added one "chain head" + + unsafe { + self.mmio.queue_notify(0, 0); + } + + return Ok(()); + } else { + return Err(buffer); + } + } + + pub fn add_rx_buffers( + &mut self, + packets: &mut RRefDeque, + collect: &mut RRefDeque, + ) { + if packets.len() == 0 { + return; + } + + while let Some(buffer) = packets.pop_front() { + let res = self.add_rx_buffer(buffer); + + if res.is_err() { + packets.push_back(res.unwrap_err()); + break; + } + } + } + + /// Returns an error if there's no free space in the TX queue, Ok otherwise + fn add_tx_packet( + &mut self, + buffer: RRef, + ) -> Result<(), RRef> { + let tx_q = &mut self.virtual_queues.as_mut().unwrap().transmit_queue; + + if let Ok(header_idx) = Self::get_free_idx(&mut self.tx_free_descriptors) { + let buffer_idx = header_idx + self.buffer_count; + let buffer_addr = buffer.as_ptr() as u64; + + // Store it so it isn't dropped + self.tx_buffers[header_idx] = Some(buffer); + + tx_q.descriptors[header_idx] = VirtqDescriptor { + addr: Self::get_addr(&self.virtio_network_headers[header_idx]), + len: core::mem::size_of::() as u32, // 10 bytes + flags: 1, // 1 is next flag + next: buffer_idx as u16, + }; + tx_q.descriptors[buffer_idx] = VirtqDescriptor { + addr: buffer_addr, + len: 1514, + flags: 0, + next: 0, + }; + + *tx_q + .available + .ring(tx_q.available.data.idx % self.queue_size) = header_idx as u16; + tx_q.available.data.idx = tx_q.available.data.idx.wrapping_add(1); + + unsafe { + self.mmio.queue_notify(1, 1); + } + return Ok(()); + } else { + return Err(buffer); + } + } + + pub fn add_tx_buffers(&mut self, packets: &mut RRefDeque) { + if packets.len() == 0 { + return; + } + + while let Some(packet) = packets.pop_front() { + let res = self.add_tx_packet(packet); + + if res.is_err() { + println!("ERROR: VIRTIO NET: COULD NOT ADD TX PACKET. NO FREE SPACE!"); + packets.push_back(res.unwrap_err()); + break; + } + } + } + + /// Adds new packets to `packets`. Returns the number of received packets + /// Returns the number of new packets found + pub fn get_received_packets( + &mut self, + collect: &mut RRefDeque, + ) -> usize { + /// We have to return the number of packets received + let mut new_packets_count = 0; + let rx_q = &mut self.virtual_queues.as_mut().unwrap().receive_queue; + + while self.rx_last_idx != rx_q.used.data.idx { + let used_element = rx_q.used.ring(self.rx_last_idx % self.queue_size); + let header_descriptor = &rx_q.descriptors[used_element.id as usize]; + let buffer_descriptor = &rx_q.descriptors[header_descriptor.next as usize]; + + if let Some(buffer) = self.rx_buffers[used_element.id as usize].take() { + // Processed packets are "collected" + collect.push_back(buffer); + new_packets_count += 1; + + // Free the descriptor + self.rx_free_descriptors[used_element.id as usize] = true; + } else { + println!("ERROR: VIRTIO NET: RX BUFFER MISSING"); + } + + self.rx_last_idx = self.rx_last_idx.wrapping_add(1); + } + + new_packets_count + } + + /// Returns the number of tx packets that have been sent + pub fn free_processed_tx_packets( + &mut self, + packets: &mut RRefDeque, + ) -> usize { + let mut freed_count = 0; + let tx_q = &mut self.virtual_queues.as_mut().unwrap().transmit_queue; + + while self.tx_last_idx != tx_q.used.data.idx { + let used_element = tx_q.used.ring(self.tx_last_idx % self.queue_size); + let header_descriptor = &tx_q.descriptors[used_element.id as usize]; + let buffer_descriptor = &tx_q.descriptors[header_descriptor.next as usize]; + + if let Some(buffer) = self.tx_buffers[used_element.id as usize].take() { + packets.push_back(buffer); + freed_count += 1; + + // Free the descriptor + self.tx_free_descriptors[used_element.id as usize] = true; + } else { + println!("ERROR: VIRTIO NET: TX BUFFER MISSING"); + } + + self.tx_last_idx = self.tx_last_idx.wrapping_add(1); + } + + freed_count + } +} diff --git a/lib/devices/virtio/src/defs.rs b/lib/devices/virtio/src/defs.rs index 2aabee18..058ccbe6 100644 --- a/lib/devices/virtio/src/defs.rs +++ b/lib/devices/virtio/src/defs.rs @@ -4,7 +4,7 @@ use alloc::{ vec::Vec, }; use console::println; -use core::{alloc::Layout, mem::size_of, usize}; +use core::{alloc::Layout, fmt::Debug, mem::size_of, usize}; // 2.6.12 Virtqueue Operation // There are two parts to virtqueue operation: supplying new available buffers to the device, and processing used buffers from the device. @@ -12,6 +12,7 @@ use core::{alloc::Layout, mem::size_of, usize}; // The driver adds outgoing (device-readable) packets to the transmit virtqueue, and then frees them after they are used. // Similarly, incoming (device-writable) buffers are added to the receive virtqueue, and processed after they are used. +#[derive(Debug)] #[repr(C, align(16))] pub struct VirtQueue { pub descriptors: Vec, @@ -114,6 +115,12 @@ impl Drop for VirtqAvailable { } } +impl Debug for VirtqAvailable { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + return self.data.fmt(f); + } +} + pub struct VirtqUsed { pub data: Box, queue_size: u16, @@ -159,3 +166,9 @@ impl Drop for VirtqUsed { } } } + +impl Debug for VirtqUsed { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + return self.data.fmt(f); + } +} diff --git a/lib/devices/virtio_net/src/lib.rs b/lib/devices/virtio_net/src/lib.rs index 0a5d99f6..d930596b 100644 --- a/lib/devices/virtio_net/src/lib.rs +++ b/lib/devices/virtio_net/src/lib.rs @@ -173,9 +173,9 @@ impl VirtioNetInner { // Setup Virtual Queues self.initialize_virtual_queue(0, &(self.virtual_queues.as_ref().unwrap().receive_queue)); - println!("Virtio Net Should Yield here!"); - self.print_device_config(); - libsyscalls::syscalls::sys_yield(); + // println!("Virtio Net Should Yield here!"); + // self.print_device_config(); + // libsyscalls::syscalls::sys_yield(); self.initialize_virtual_queue(1, &(self.virtual_queues.as_ref().unwrap().transmit_queue)); From 2d960572e46c279001fe6dd7f5accdf30fa661ac Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Mon, 23 Aug 2021 13:00:31 -0700 Subject: [PATCH 04/15] Fixed minor printing error --- domains/sys/driver/virtio_backend/src/defs.rs | 12 +++++++++--- domains/sys/driver/virtio_backend/src/main.rs | 2 ++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/domains/sys/driver/virtio_backend/src/defs.rs b/domains/sys/driver/virtio_backend/src/defs.rs index c09dfc9d..c4ebbff7 100644 --- a/domains/sys/driver/virtio_backend/src/defs.rs +++ b/domains/sys/driver/virtio_backend/src/defs.rs @@ -1,4 +1,4 @@ -use virtio_device::defs::VirtQueue; +use virtio_device::defs::{VirtQueue, VirtqAvailablePacked, VirtqUsedPacked}; pub const MAX_SUPPORTED_QUEUES: u16 = 3; @@ -19,9 +19,15 @@ pub struct VirtioBackendQueue { } impl VirtioBackendQueue { - pub fn get_driver_queue(&mut self) -> &mut VirtQueue { + pub fn get_driver_queue(&mut self) -> &mut VirtqAvailablePacked { unsafe { - return &mut *(self.queue_driver as *mut VirtQueue); + return &mut *(self.queue_driver as *mut VirtqAvailablePacked); + } + } + + pub fn get_device_queue(&mut self) -> &mut VirtqUsedPacked { + unsafe { + return &mut *(self.queue_driver as *mut VirtqUsedPacked); } } } diff --git a/domains/sys/driver/virtio_backend/src/main.rs b/domains/sys/driver/virtio_backend/src/main.rs index c9fc4e66..7e87d5b8 100644 --- a/domains/sys/driver/virtio_backend/src/main.rs +++ b/domains/sys/driver/virtio_backend/src/main.rs @@ -133,6 +133,8 @@ fn virtio_backend() { for q in &mut backend.lock().backend_queues { if let Some(queue) = q.as_mut() { println!("Driver Queue: {:#?}", queue.get_driver_queue()); + println!("Device Queue: {:#?}", queue.get_device_queue()); + } } From cd55c72adaac94127897f482f101425765dec08a Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Tue, 24 Aug 2021 20:25:58 -0700 Subject: [PATCH 05/15] Added new Virtio Net Domain --- Makefile | 1 + domains/Cargo.lock | 39 ++ domains/Cargo.toml | 1 + domains/sys/driver/virtio_net_mmio/Cargo.toml | 39 ++ .../sys/driver/virtio_net_mmio/src/main.rs | 173 +++++++ .../sys/driver/virtio_net_mmio/src/nullnet.rs | 68 +++ .../driver/virtio_net_mmio/src/virtio_net.rs | 473 ++++++++++++++++++ domains/sys/init/Cargo.toml | 2 + domains/sys/init/src/main.rs | 9 + domains/usr/proxy/src/main.rs | 2 + interface/Cargo.lock | 81 +++ interface/Cargo.toml | 1 + interface/src/domain_create.rs | 10 + interface/src/proxy.rs | 6 +- kernel/Cargo.lock | 63 ++- kernel/Cargo.toml | 1 + lib/devices/virtio_backend/Cargo.lock | 264 ++++++++++ lib/devices/virtio_backend/Cargo.toml | 21 + lib/devices/virtio_backend/src/defs.rs | 3 + lib/devices/virtio_backend/src/lib.rs | 13 + lib/devices/virtio_backend/src/pci.rs | 56 +++ lib/devices/virtio_net_mmio/Cargo.lock | 264 ++++++++++ lib/devices/virtio_net_mmio/Cargo.toml | 23 + lib/devices/virtio_net_mmio/src/lib.rs | 471 +++++++++++++++++ lib/devices/virtio_net_mmio/src/pci.rs | 56 +++ lib/external/volatile_accessor/src/lib.rs | 51 +- tools/rv6-mkfs/Cargo.lock | 81 +++ 27 files changed, 2253 insertions(+), 19 deletions(-) create mode 100644 domains/sys/driver/virtio_net_mmio/Cargo.toml create mode 100644 domains/sys/driver/virtio_net_mmio/src/main.rs create mode 100644 domains/sys/driver/virtio_net_mmio/src/nullnet.rs create mode 100644 domains/sys/driver/virtio_net_mmio/src/virtio_net.rs create mode 100644 lib/devices/virtio_backend/Cargo.lock create mode 100644 lib/devices/virtio_backend/Cargo.toml create mode 100644 lib/devices/virtio_backend/src/defs.rs create mode 100644 lib/devices/virtio_backend/src/lib.rs create mode 100644 lib/devices/virtio_backend/src/pci.rs create mode 100644 lib/devices/virtio_net_mmio/Cargo.lock create mode 100644 lib/devices/virtio_net_mmio/Cargo.toml create mode 100644 lib/devices/virtio_net_mmio/src/lib.rs create mode 100644 lib/devices/virtio_net_mmio/src/pci.rs diff --git a/Makefile b/Makefile index 31b5a423..86a7249a 100644 --- a/Makefile +++ b/Makefile @@ -73,6 +73,7 @@ domain_list := $(addprefix domains/build/, \ virtio_net \ virtio_block \ virtio_backend \ + virtio_net_mmio \ nvme \ tpm \ bdev_shadow \ diff --git a/domains/Cargo.lock b/domains/Cargo.lock index 200e44da..203dafbc 100644 --- a/domains/Cargo.lock +++ b/domains/Cargo.lock @@ -334,6 +334,7 @@ dependencies = [ "spin 0.5.3", "syscalls", "unwind", + "virtio_backend_trusted", ] [[package]] @@ -755,6 +756,7 @@ dependencies = [ "pc-keyboard", "spin 0.5.3", "syscalls", + "virtio_backend_trusted", ] [[package]] @@ -1014,6 +1016,20 @@ dependencies = [ "virtio_device", ] +[[package]] +name = "virtio_backend_trusted" +version = "0.1.0" +dependencies = [ + "console", + "hashbrown 0.7.2", + "libsyscalls", + "libtime", + "malloc", + "spin 0.5.3", + "virtio_device", + "volatile_accessor", +] + [[package]] name = "virtio_block" version = "0.1.0" @@ -1081,6 +1097,29 @@ dependencies = [ "virtio_network_device", ] +[[package]] +name = "virtio_net_mmio" +version = "0.1.0" +dependencies = [ + "console", + "hashbrown 0.7.2", + "interface", + "libbenchnet", + "libsyscalls", + "libtime", + "malloc", + "pci_driver", + "platform", + "protocol", + "redhttpd", + "smolnet", + "smoltcp", + "spin 0.5.3", + "syscalls", + "virtio_device", + "virtio_network_device", +] + [[package]] name = "virtio_network_device" version = "0.1.0" diff --git a/domains/Cargo.toml b/domains/Cargo.toml index 5080e003..29390a8f 100644 --- a/domains/Cargo.toml +++ b/domains/Cargo.toml @@ -11,6 +11,7 @@ members = [ "sys/driver/virtio_net", "sys/driver/virtio_block", "sys/driver/virtio_backend", + "sys/driver/virtio_net_mmio", "sys/init", "usr/proxy", "usr/shadow/bdev", diff --git a/domains/sys/driver/virtio_net_mmio/Cargo.toml b/domains/sys/driver/virtio_net_mmio/Cargo.toml new file mode 100644 index 00000000..0860b2e5 --- /dev/null +++ b/domains/sys/driver/virtio_net_mmio/Cargo.toml @@ -0,0 +1,39 @@ +[package] +name = "virtio_net_mmio" +version = "0.1.0" +authors = ["RedLeaf Team"] +edition = "2018" + +[dependencies] +libsyscalls = { path = "../../../../lib/core/libsyscalls" } +libtime = { path = "../../../../lib/core/libtime" } +console = { path = "../../../../lib/core/console" } +malloc = { path = "../../../../lib/core/malloc" } +libbenchnet = { path = "../../../lib/libbenchnet" } +spin = { path = "../../../../lib/core/spin-rs" } + +smolnet = { path = "../../../../domains/lib/smolnet" } +hashbrown = "0.7.2" +redhttpd = { path = "../../../lib/redhttpd" } + +virtio_device = { path = "../../../../lib/devices/virtio" } +virtio_network_device = { path = "../../../../lib/devices/virtio_net" } + +# Interfaces +syscalls = { path = "../../../../lib/core/interfaces/syscalls" } +pci_driver = { path = "../../../../lib/core/interfaces/dev/pci/pci_driver" } +protocol = { path = "../../../../lib/core/interfaces/protocol" } +platform = { path = "../../../../lib/core/interfaces/platform" } +interface = { path = "../../../../interface/generated" } + + +[dependencies.smoltcp] +path = "../../../../lib/external/smoltcp" +default-features = false +features = ["alloc", "proto-ipv4", "socket-tcp", "socket-icmp", "ethernet"] + +[features] +default = [ +] + +virtio_net = [] diff --git a/domains/sys/driver/virtio_net_mmio/src/main.rs b/domains/sys/driver/virtio_net_mmio/src/main.rs new file mode 100644 index 00000000..b17bf26c --- /dev/null +++ b/domains/sys/driver/virtio_net_mmio/src/main.rs @@ -0,0 +1,173 @@ +#![no_std] +#![no_main] +#![feature( + box_syntax, + const_fn, + const_raw_ptr_to_usize_cast, + const_in_array_repeat_expressions, + untagged_unions, + maybe_uninit_extra +)] + +extern crate alloc; +extern crate malloc; + +mod nullnet; + +use alloc::collections::VecDeque; +use alloc::sync::Arc; +use alloc::vec::Vec; +use alloc::{boxed::Box, collections::BTreeMap}; +use core::{borrow::BorrowMut, panic::PanicInfo, pin::Pin, usize}; +use syscalls::{Heap, Syscall}; + +use console::{print, println}; +use interface::{net::Net, rpc::RpcResult}; +use libsyscalls::syscalls::sys_backtrace; +pub use platform::PciBarAddr; +use spin::Mutex; + +pub use interface::error::{ErrorKind, Result}; +use virtio_network_device::pci::PciFactory; +use virtio_network_device::VirtioNetInner; + +use interface::rref::{RRef, RRefDeque}; + +use smolnet::{self, SmolPhy}; + +pub use interface::net::NetworkStats; + +pub struct VirtioNet(Arc>); + +impl interface::net::Net for VirtioNet { + fn clone_net(&self) -> RpcResult> { + Ok(box Self(self.0.clone())) + } + + fn submit_and_poll( + &self, + mut packets: &mut VecDeque>, + mut collect: &mut VecDeque>, + tx: bool, + ) -> RpcResult> { + unimplemented!() + } + + /// If `tx` is true, packets in packets are for transmitting, else they are receive buffers + fn submit_and_poll_rref( + &self, + mut packets: RRefDeque<[u8; 1514], 32>, + mut collect: RRefDeque<[u8; 1514], 32>, + tx: bool, + pkt_len: usize, + ) -> RpcResult, RRefDeque<[u8; 1514], 32>)>> { + let mut device = self.0.lock(); + + let mut new_packet_count = 0; + + if tx { + new_packet_count = device.free_processed_tx_packets(&mut collect); + device.add_tx_buffers(&mut packets); + } else { + new_packet_count = device.get_received_packets(&mut collect); + device.add_rx_buffers(&mut packets, &mut collect); + } + + Ok(Ok((new_packet_count, packets, collect))) + } + + fn poll(&self, mut collect: &mut VecDeque>, tx: bool) -> RpcResult> { + unimplemented!() + } + + fn poll_rref( + &self, + mut collect: RRefDeque<[u8; 1514], 512>, + tx: bool, + ) -> RpcResult)>> { + // let mut new_packet_count = 0; + // let device = self.0.lock(); + + // if tx { + // new_packet_count = device.free_processed_tx_packets(&mut collect); + // } else { + // new_packet_count = device.get_received_packets(&mut collect); + // } + + // Ok(Ok((new_packet_count, collect))) + Ok(Ok((0, collect))) + } + + fn get_stats(&self) -> RpcResult> { + // unimplemented!() + Ok(Ok(NetworkStats { + tx_count: 0, + rx_count: 0, + tx_dma_ok: 0, + rx_dma_ok: 0, + rx_missed: 0, + rx_crc_err: 0, + })) + } + + fn test_domain_crossing(&self) -> RpcResult<()> { + unimplemented!() + } +} + +#[no_mangle] +pub fn trusted_entry( + s: Box, + heap: Box, + pci: Box, +) -> Box { + libsyscalls::syscalls::init(s); + interface::rref::init(heap, libsyscalls::syscalls::sys_get_current_domain_id()); + + // libbenchnet::run_fwd_udptest_rref(&net, 1514); + + // VIRTIO DEMO LOOP + // Run SmolNet + + // let mut smol = SmolPhy::new(Box::new(net)); + + // use smoltcp::iface::{EthernetInterfaceBuilder, NeighborCache}; + // use smoltcp::socket::SocketSet; + // use smoltcp::time::Instant; + // use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; + + // let neighbor_cache = NeighborCache::new(BTreeMap::new()); + + // let ip_addresses = [IpCidr::new(IpAddress::v4(10, 10, 10, 10), 24)]; + // let mac_address = [0x90, 0xe2, 0xba, 0xb3, 0xb9, 0x10]; + // let mut iface = EthernetInterfaceBuilder::new(smol) + // .ethernet_addr(EthernetAddress::from_bytes(&mac_address)) + // .neighbor_cache(neighbor_cache) + // .ip_addrs(ip_addresses) + // .finalize(); + + // let mut sockets = SocketSet::new(Vec::with_capacity(512)); + + // let mut httpd = redhttpd::Httpd::new(); + + // loop { + // iface.device_mut().do_rx(); + + // let current = libtime::get_ns_time() / 1000000; + // let timestamp = Instant::from_millis(current as i64); + + // iface.poll(&mut sockets, timestamp); + // httpd.handle(&mut sockets); + // iface.device_mut().do_tx(); + // } + + Box::new(nullnet::NullNet::new()) +} + +// This function is called on panic. +#[panic_handler] +fn panic(info: &PanicInfo) -> ! { + println!("{:?}", info); + sys_backtrace(); + loop {} +} diff --git a/domains/sys/driver/virtio_net_mmio/src/nullnet.rs b/domains/sys/driver/virtio_net_mmio/src/nullnet.rs new file mode 100644 index 00000000..9b19a8ee --- /dev/null +++ b/domains/sys/driver/virtio_net_mmio/src/nullnet.rs @@ -0,0 +1,68 @@ +use alloc::boxed::Box; +use alloc::collections::VecDeque; +use alloc::vec::Vec; +use interface::error::Result; +use interface::net::NetworkStats; +use interface::rpc::RpcResult; +use interface::rref::RRefDeque; + +pub struct NullNet {} + +impl NullNet { + pub fn new() -> Self { + Self {} + } +} + +impl interface::net::Net for NullNet { + fn clone_net(&self) -> RpcResult> { + Ok(box Self::new()) + } + + fn submit_and_poll( + &self, + packets: &mut VecDeque>, + collect: &mut VecDeque>, + _tx: bool, + ) -> RpcResult> { + let ret = packets.len(); + while let Some(pkt) = packets.pop_front() { + collect.push_back(pkt); + } + Ok(Ok(ret)) + } + + fn submit_and_poll_rref( + &self, + mut packets: RRefDeque<[u8; 1514], 32>, + mut collect: RRefDeque<[u8; 1514], 32>, + _tx: bool, + _pkt_len: usize, + ) -> RpcResult, RRefDeque<[u8; 1514], 32>)>> { + while let Some(pkt) = packets.pop_front() { + collect.push_back(pkt); + } + + Ok(Ok((collect.len(), packets, collect))) + } + + fn poll(&self, _collect: &mut VecDeque>, _tx: bool) -> RpcResult> { + Ok(Ok(0)) + } + + fn poll_rref( + &self, + collect: RRefDeque<[u8; 1514], 512>, + _tx: bool, + ) -> RpcResult)>> { + Ok(Ok((0, collect))) + } + + fn get_stats(&self) -> RpcResult> { + Ok(Ok(NetworkStats::new())) + } + + fn test_domain_crossing(&self) -> RpcResult<()> { + Ok(()) + } +} diff --git a/domains/sys/driver/virtio_net_mmio/src/virtio_net.rs b/domains/sys/driver/virtio_net_mmio/src/virtio_net.rs new file mode 100644 index 00000000..ea6b3a84 --- /dev/null +++ b/domains/sys/driver/virtio_net_mmio/src/virtio_net.rs @@ -0,0 +1,473 @@ +#![no_std] +#![no_main] +#![feature( + box_syntax, + const_fn, + const_raw_ptr_to_usize_cast, + const_in_array_repeat_expressions, + untagged_unions, + maybe_uninit_extra +)] + +extern crate alloc; + +use core::usize; + +use alloc::alloc::{alloc, Layout}; +use alloc::sync::Arc; +use alloc::vec; +use alloc::vec::Vec; +use console::println; +use interface::rref::{RRef, RRefDeque}; +use spin::Mutex; +use virtio_device::defs::{ + VirtQueue, VirtqAvailable, VirtqAvailablePacked, VirtqDescriptor, VirtqUsed, VirtqUsedElement, + VirtqUsedPacked, +}; +use virtio_device::{Mmio, VirtioDeviceStatus}; + +use crate::virtio_device_config_modified; + +#[repr(C, packed)] +pub struct VirtioNetworkDeviceConfig { + mac: [u8; 6], + status: u16, + // Not available without negotiating features VIRTIO_NET_F_MQ and VIRTIO_NET_F_MTU + // max_virtqueue_pairs: u16, + // mtu: u16, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct VirtioNetworkHeader { + pub flags: u8, + pub gso_type: u8, + pub header_length: u16, + pub gso_size: u16, + pub csum_start: u16, + pub csum_offset: u16, + // pub num_buffers: u16, +} + +struct VirtualQueues { + receive_queue: VirtQueue, + transmit_queue: VirtQueue, +} + +type NetworkPacketBuffer = [u8; 1514]; + +pub struct VirtioNetInner { + mmio: Mmio, + virtual_queues: Option, // None until init() is called + + /// This is the size of the queues used by the device, it is read during init(). + /// It would be less annoying to use if it were usize but it truly is a u16 value. + queue_size: u16, + + /// This tracks the maximum number of buffers or descriptor chains we can simultaneiously have. + /// For the network driver, each network packet requires two descriptors so this will be + /// queue_size / 2. + buffer_count: usize, + + /// Dummy VirtioNetHeaders. + /// The driver doesn't actually use these but they are required by the spec + virtio_network_headers: Vec, + + /// Tracks which descriptors on the queue are free + rx_free_descriptors: Vec, + /// Tracks which descriptors on the queue are free + tx_free_descriptors: Vec, + + /// The last index (of the used ring) that was checked by the driver + rx_last_idx: u16, + /// The last index (of the used ring) that was checked by the driver + tx_last_idx: u16, + + rx_buffers: Vec>>, + tx_buffers: Vec>>, +} + +impl VirtioNetInner { + /// Returns an initialized VirtioNet from a base address. + pub unsafe fn new(mmio_base: usize) -> Self { + Self { + mmio: Mmio::new(mmio_base), + + queue_size: 0, // We will update this (and the vecs) in init() + buffer_count: 0, + + virtual_queues: None, + + virtio_network_headers: vec![], + + rx_free_descriptors: vec![], + tx_free_descriptors: vec![], + + rx_buffers: vec![], + tx_buffers: vec![], + + rx_last_idx: 0, + tx_last_idx: 0, + } + } + + pub fn init(&mut self) { + println!("Initializing Virtio Network Device"); + + // VIRTIO DEVICE INIT + // https://docs.oasis-open.org/virtio/virtio/v1.1/cs01/virtio-v1.1-cs01.html#x1-920001 + // + // Reset the device. + // Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. + // Set the DRIVER status bit: the guest OS knows how to drive the device. + // Read device feature bits, and write the subset of feature bits understood by the OS and driver to the device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration fields to check that it can support the device before accepting it. + // Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. + // Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. + // Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup, reading and possibly writing the device’s virtio configuration space, and population of virtqueues. + // Set the DRIVER_OK status bit. At this point the device is “live”. + + // Reset the device + // Failing to do this DOES cause errors, don't ask how I know *sigh* + self.mmio.accessor.write_device_status(0); + Mmio::memory_fence(); + + // Acknowledge Device + unsafe { + self.mmio + .update_device_status(VirtioDeviceStatus::Acknowledge); + self.mmio.update_device_status(VirtioDeviceStatus::Driver); // But do we really know how to drive the device? + } + + self.negotiate_features(); + + // Tell the Device that feature Negotiation is complete + unsafe { + self.mmio + .update_device_status(VirtioDeviceStatus::FeaturesOk); + } + + // Check that Features OK Bit is still set! + // self.print_device_status(); + if (self.mmio.accessor.read_device_status() & VirtioDeviceStatus::FeaturesOk.value()) == 0 { + panic!("Failed to negotiate Virtio Net features!"); + } + + // Read the queue size + // This value is that largest possible queue size so we will use it to initialize all of our vectors + let queue_size = self.mmio.accessor.read_queue_size(); + if queue_size == 0 { + panic!("ERROR: VIRTIO NET: BAD QUEUE SIZE!"); + } + + self.queue_size = queue_size; + self.buffer_count = (self.queue_size / 2) as usize; // Each buffer requires two descriptors + + unsafe { + self.setup_virtual_queues(); + } + + self.initialize_vectors(); + + // Setup Virtual Queues + self.initialize_virtual_queue(0, &(self.virtual_queues.as_ref().unwrap().receive_queue)); + + // println!("Virtio Net Should Yield here!"); + // self.print_device_config(); + // libsyscalls::syscalls::sys_yield(); + + virtio_device_config_modified(); + + self.initialize_virtual_queue(1, &(self.virtual_queues.as_ref().unwrap().transmit_queue)); + + virtio_device_config_modified(); + + // Tell the Device we're all done, even though we aren't + unsafe { self.mmio.update_device_status(VirtioDeviceStatus::DriverOk) }; + + // self.print_device_status(); + + // self.mmio.accessor.write_queue_select(0); + // self.print_device_config(); + // self.mmio.accessor.write_queue_select(1); + // self.print_device_config(); + + println!("VIRTIO NET READY!"); + } + + /// Negotiates Virtio Driver Features + fn negotiate_features(&mut self) { + let mut driver_features: u32 = 0; + driver_features |= 1 << 5; // Enable Device MAC Address + driver_features |= 1 << 16; // Enable Device Status + + self.mmio.accessor.write_driver_feature(driver_features); // Should be &'d with device_features + } + + pub fn print_device_config(&mut self) { + let mut cfg = unsafe { self.mmio.read_common_config() }; + println!("{:#?}", cfg); + } + + pub fn print_device_status(&mut self) { + let device_status = self.mmio.accessor.read_device_status(); + println!("Device Status Bits: {:b}", device_status); + } + + /// Initializes all the vectors using the set buffer_count + fn initialize_vectors(&mut self) { + self.virtio_network_headers = vec![ + VirtioNetworkHeader { + csum_offset: 0, + csum_start: 0, + flags: 0, + gso_size: 0, + gso_type: 0, + header_length: 0, + }; + self.buffer_count + ]; + + self.rx_free_descriptors = vec![true; self.buffer_count]; + self.tx_free_descriptors = vec![true; self.buffer_count]; + + self.rx_buffers = Vec::with_capacity(self.buffer_count); + self.rx_buffers.resize_with(self.buffer_count, || None); + self.tx_buffers = Vec::with_capacity(self.buffer_count); + self.tx_buffers.resize_with(self.buffer_count, || None); + } + + unsafe fn setup_virtual_queues(&mut self) { + self.virtual_queues = Some(VirtualQueues { + receive_queue: VirtQueue { + descriptors: vec![VirtqDescriptor::default(); self.queue_size as usize], + available: VirtqAvailable::new(self.queue_size), + used: VirtqUsed::new(self.queue_size), + }, + transmit_queue: VirtQueue { + descriptors: vec![VirtqDescriptor::default(); self.queue_size as usize], + available: VirtqAvailable::new(self.queue_size), + used: VirtqUsed::new(self.queue_size), + }, + }); + } + + /// Receive Queues must be 2*N and Transmit Queues must be 2*N + 1 + /// For example, Receive Queue must be 0 and Transmit Queue must be 1 + fn initialize_virtual_queue(&self, queue_index: u16, virt_queue: &VirtQueue) { + self.mmio.accessor.write_queue_select(queue_index); + + self.mmio + .accessor + .write_queue_desc(virt_queue.descriptors.as_ptr() as u64); + self.mmio.accessor.write_queue_driver( + (virt_queue.available.data.as_ref() as *const VirtqAvailablePacked) as u64, + ); + self.mmio + .accessor + .write_queue_device((virt_queue.used.data.as_ref() as *const VirtqUsedPacked) as u64); + self.mmio.accessor.write_queue_enable(1); + } + + /// Returns a free descriptor chain index + /// For Virtio Net, the VirtioNetworkHeader is placed at i and the Packet Buffer will be placed at i + self.buffer_count + fn get_free_idx(free_buffers: &mut Vec) -> Result { + for i in 0..free_buffers.len() { + if free_buffers[i] { + free_buffers[i] = false; + return Ok(i); + } + } + + return Err(()); + } + + #[inline] + fn get_addr(obj: &T) -> u64 { + (obj as *const T) as u64 + } + + /// If the buffer can't be added, it is returned in the Err() + fn add_rx_buffer( + &mut self, + buffer: RRef, + ) -> Result<(), RRef> { + let rx_q = &mut self.virtual_queues.as_mut().unwrap().receive_queue; + + if let Ok(header_idx) = Self::get_free_idx(&mut self.rx_free_descriptors) { + let buffer_idx = header_idx + self.buffer_count; + let buffer_addr = buffer.as_ptr() as u64; + + // Store it so it isn't dropped + self.rx_buffers[header_idx] = Some(buffer); + + // One descriptor points at the network header, chain this with a descriptor to the buffer + // Header + rx_q.descriptors[header_idx] = VirtqDescriptor { + addr: Self::get_addr(&self.virtio_network_headers[header_idx]), + len: core::mem::size_of::() as u32, // 10 bytes + // 1 is NEXT FLAG + // 2 is WRITABLE FLAG + flags: 1 | 2, + next: buffer_idx as u16, + }; + // Actual Buffer + rx_q.descriptors[buffer_idx] = VirtqDescriptor { + addr: buffer_addr, + len: 1514, + flags: 2, + next: 0, + }; + + // Mark the buffer as usable + *rx_q + .available + .ring(rx_q.available.data.idx % self.queue_size) = header_idx as u16; + rx_q.available.data.idx = rx_q.available.data.idx.wrapping_add(1); // We only added one "chain head" + + unsafe { + self.mmio.queue_notify(0, 0); + } + + return Ok(()); + } else { + return Err(buffer); + } + } + + pub fn add_rx_buffers( + &mut self, + packets: &mut RRefDeque, + collect: &mut RRefDeque, + ) { + if packets.len() == 0 { + return; + } + + while let Some(buffer) = packets.pop_front() { + let res = self.add_rx_buffer(buffer); + + if res.is_err() { + packets.push_back(res.unwrap_err()); + break; + } + } + } + + /// Returns an error if there's no free space in the TX queue, Ok otherwise + fn add_tx_packet( + &mut self, + buffer: RRef, + ) -> Result<(), RRef> { + let tx_q = &mut self.virtual_queues.as_mut().unwrap().transmit_queue; + + if let Ok(header_idx) = Self::get_free_idx(&mut self.tx_free_descriptors) { + let buffer_idx = header_idx + self.buffer_count; + let buffer_addr = buffer.as_ptr() as u64; + + // Store it so it isn't dropped + self.tx_buffers[header_idx] = Some(buffer); + + tx_q.descriptors[header_idx] = VirtqDescriptor { + addr: Self::get_addr(&self.virtio_network_headers[header_idx]), + len: core::mem::size_of::() as u32, // 10 bytes + flags: 1, // 1 is next flag + next: buffer_idx as u16, + }; + tx_q.descriptors[buffer_idx] = VirtqDescriptor { + addr: buffer_addr, + len: 1514, + flags: 0, + next: 0, + }; + + *tx_q + .available + .ring(tx_q.available.data.idx % self.queue_size) = header_idx as u16; + tx_q.available.data.idx = tx_q.available.data.idx.wrapping_add(1); + + unsafe { + self.mmio.queue_notify(1, 1); + } + return Ok(()); + } else { + return Err(buffer); + } + } + + pub fn add_tx_buffers(&mut self, packets: &mut RRefDeque) { + if packets.len() == 0 { + return; + } + + while let Some(packet) = packets.pop_front() { + let res = self.add_tx_packet(packet); + + if res.is_err() { + println!("ERROR: VIRTIO NET: COULD NOT ADD TX PACKET. NO FREE SPACE!"); + packets.push_back(res.unwrap_err()); + break; + } + } + } + + /// Adds new packets to `packets`. Returns the number of received packets + /// Returns the number of new packets found + pub fn get_received_packets( + &mut self, + collect: &mut RRefDeque, + ) -> usize { + /// We have to return the number of packets received + let mut new_packets_count = 0; + let rx_q = &mut self.virtual_queues.as_mut().unwrap().receive_queue; + + while self.rx_last_idx != rx_q.used.data.idx { + let used_element = rx_q.used.ring(self.rx_last_idx % self.queue_size); + let header_descriptor = &rx_q.descriptors[used_element.id as usize]; + let buffer_descriptor = &rx_q.descriptors[header_descriptor.next as usize]; + + if let Some(buffer) = self.rx_buffers[used_element.id as usize].take() { + // Processed packets are "collected" + collect.push_back(buffer); + new_packets_count += 1; + + // Free the descriptor + self.rx_free_descriptors[used_element.id as usize] = true; + } else { + println!("ERROR: VIRTIO NET: RX BUFFER MISSING"); + } + + self.rx_last_idx = self.rx_last_idx.wrapping_add(1); + } + + new_packets_count + } + + /// Returns the number of tx packets that have been sent + pub fn free_processed_tx_packets( + &mut self, + packets: &mut RRefDeque, + ) -> usize { + let mut freed_count = 0; + let tx_q = &mut self.virtual_queues.as_mut().unwrap().transmit_queue; + + while self.tx_last_idx != tx_q.used.data.idx { + let used_element = tx_q.used.ring(self.tx_last_idx % self.queue_size); + let header_descriptor = &tx_q.descriptors[used_element.id as usize]; + let buffer_descriptor = &tx_q.descriptors[header_descriptor.next as usize]; + + if let Some(buffer) = self.tx_buffers[used_element.id as usize].take() { + packets.push_back(buffer); + freed_count += 1; + + // Free the descriptor + self.tx_free_descriptors[used_element.id as usize] = true; + } else { + println!("ERROR: VIRTIO NET: TX BUFFER MISSING"); + } + + self.tx_last_idx = self.tx_last_idx.wrapping_add(1); + } + + freed_count + } +} diff --git a/domains/sys/init/Cargo.toml b/domains/sys/init/Cargo.toml index 5f83bf37..27737c16 100644 --- a/domains/sys/init/Cargo.toml +++ b/domains/sys/init/Cargo.toml @@ -15,6 +15,8 @@ spin = { path = "../../../lib/core/spin-rs" } libtime = { path = "../../../lib/core/libtime" } pc-keyboard = "0.3.1" +virtio_backend_trusted = { path = "../../../lib/devices/virtio_backend" } + [dependencies.lazy_static] version = "1.3.0" features = ["spin_no_std"] diff --git a/domains/sys/init/src/main.rs b/domains/sys/init/src/main.rs index 9b5128c1..8bcb75d2 100644 --- a/domains/sys/init/src/main.rs +++ b/domains/sys/init/src/main.rs @@ -20,6 +20,7 @@ use interface::rref::RRefVec; use libsyscalls::syscalls::{ sys_backtrace, sys_create_thread, sys_readch_kbd, sys_recv_int, sys_yield, }; +use virtio_backend_trusted::defs::VirtioMMIOConfiguration; #[cfg(feature = "test_guard_page")] fn test_stack_exhaustion() -> u64 { @@ -110,6 +111,7 @@ pub fn trusted_entry( create_virtio_net: Arc, create_virtio_block: Arc, create_virtio_backend: Arc, + create_virtio_net_mmio: Arc, create_net_shadow: Arc, create_nvme_shadow: Arc, create_nvme: Arc, @@ -195,6 +197,7 @@ pub fn trusted_entry( create_virtio_net, create_virtio_block, create_virtio_backend, + create_virtio_net_mmio, create_nvme, create_net_shadow, create_nvme_shadow, @@ -250,6 +253,12 @@ pub fn trusted_entry( .as_domain_create_CreateVirtioBackend() .create_domain_virtio_backend(); + let (_, net) = proxy + .as_domain_create_CreateVirtioNetMMIO() + .create_domain_virtio_net_mmio(Box::new(VirtioMMIOConfiguration { + configuration_address: 0x100000, + })); + #[cfg(all(not(feature = "shadow"), not(feature = "virtnet")))] let (_, net) = proxy.as_create_ixgbe().create_domain_ixgbe(pci.pci_clone()); diff --git a/domains/usr/proxy/src/main.rs b/domains/usr/proxy/src/main.rs index 7d4fb4d7..59d96237 100644 --- a/domains/usr/proxy/src/main.rs +++ b/domains/usr/proxy/src/main.rs @@ -26,6 +26,7 @@ pub fn trusted_entry( create_virtio_net: alloc::sync::Arc, create_virtio_block: Arc, create_virtio_backend: Arc, + create_virtio_net_mmio: Arc, create_nvme: alloc::sync::Arc, create_net_shadow: alloc::sync::Arc, create_nvme_shadow: alloc::sync::Arc, @@ -51,6 +52,7 @@ pub fn trusted_entry( create_virtio_net, create_virtio_block, create_virtio_backend, + create_virtio_net_mmio, create_net_shadow, create_nvme_shadow, create_nvme, diff --git a/interface/Cargo.lock b/interface/Cargo.lock index 6b00af05..88845724 100644 --- a/interface/Cargo.lock +++ b/interface/Cargo.lock @@ -34,6 +34,12 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "console" version = "0.1.0" @@ -65,8 +71,15 @@ dependencies = [ "pci_driver", "spin", "syscalls", + "virtio_backend_trusted", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libsyscalls" version = "0.1.0" @@ -77,6 +90,32 @@ dependencies = [ "syscalls", ] +[[package]] +name = "libtime" +version = "0.1.0" +dependencies = [ + "console", + "libsyscalls", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "malloc" +version = "0.1.0" +dependencies = [ + "libsyscalls", + "slabmalloc", + "spin", +] + [[package]] name = "num-derive" version = "0.3.2" @@ -140,6 +179,13 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "slabmalloc" +version = "0.7.0" +dependencies = [ + "log", +] + [[package]] name = "spin" version = "0.5.3" @@ -170,3 +216,38 @@ name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "virtio_backend_trusted" +version = "0.1.0" +dependencies = [ + "console", + "hashbrown", + "libsyscalls", + "libtime", + "malloc", + "spin", + "virtio_device", + "volatile_accessor", +] + +[[package]] +name = "virtio_device" +version = "0.1.0" +dependencies = [ + "console", + "libsyscalls", + "libtime", + "malloc", + "volatile_accessor", +] + +[[package]] +name = "volatile_accessor" +version = "0.1.0" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn", +] diff --git a/interface/Cargo.toml b/interface/Cargo.toml index 84c394d5..1743650e 100644 --- a/interface/Cargo.toml +++ b/interface/Cargo.toml @@ -16,6 +16,7 @@ pci_driver = { path = "../lib/core/interfaces/dev/pci/pci_driver/", version = "0 console = { path = "../lib/core/console", version = "0.1.0" } spin = { path = "../lib/core/spin-rs" } hashbrown = "0.7.2" +virtio_backend_trusted = { path = "../lib/devices/virtio_backend" } diff --git a/interface/src/domain_create.rs b/interface/src/domain_create.rs index f5889389..303f53b3 100644 --- a/interface/src/domain_create.rs +++ b/interface/src/domain_create.rs @@ -13,6 +13,7 @@ use crate::{ use alloc::boxed::Box; use alloc::sync::Arc; use syscalls::{Domain, Heap, Interrupt}; +use virtio_backend_trusted::defs::VirtioMMIOConfiguration; #[domain_create(path = "dom_proxy")] pub trait CreateProxy { @@ -25,6 +26,7 @@ pub trait CreateProxy { create_virtio_net: Arc, create_virtio_block: Arc, create_virtio_backend: Arc, + create_virtio_net_mmio: Arc, create_nvme: Arc, create_net_shadow: Arc, create_nvme_shadow: Arc, @@ -92,6 +94,14 @@ pub trait CreateVirtioBackend: Send + Sync { fn create_domain_virtio_backend(&self) -> (Box, ()); } +#[domain_create(path = "virtio_net_mmio")] +pub trait CreateVirtioNetMMIO: Send + Sync { + fn create_domain_virtio_net_mmio( + &self, + config: Box, + ) -> (Box, Box); +} + #[domain_create(path = "net_shadow")] pub trait CreateNetShadow: Send + Sync { fn create_domain_net_shadow( diff --git a/interface/src/proxy.rs b/interface/src/proxy.rs index 41e7b14c..0a5b92ca 100644 --- a/interface/src/proxy.rs +++ b/interface/src/proxy.rs @@ -3,7 +3,7 @@ use crate::domain_create::{ CreateAHCI, CreateBDevShadow, CreateBenchnet, CreateBenchnvme, CreateDomC, CreateDomD, CreateIxgbe, CreateMemBDev, CreateNetShadow, CreateNvme, CreateNvmeShadow, CreatePCI, CreateRv6, CreateRv6FS, CreateRv6Net, CreateRv6NetShadow, CreateRv6Usr, CreateShadow, - CreateVirtioBackend, CreateVirtioBlock, CreateVirtioNet, + CreateVirtioBackend, CreateVirtioBlock, CreateVirtioNet, CreateVirtioNetMMIO, }; use alloc::boxed::Box; use alloc::sync::Arc; @@ -25,6 +25,7 @@ pub trait Proxy: + CreateVirtioNet + CreateVirtioBlock + CreateVirtioBackend + + CreateVirtioNetMMIO { // necessary because rust doesn't support trait object upcasting fn as_domain_create_CreateVirtioNet(&self) -> Arc; @@ -34,6 +35,9 @@ pub trait Proxy: fn as_domain_create_CreateVirtioBackend( &self, ) -> Arc; + fn as_domain_create_CreateVirtioNetMMIO( + &self, + ) -> Arc; fn as_domain_create_CreateIxgbe(&self) -> Arc; fn as_domain_create_CreateDomD(&self) -> Arc; fn as_domain_create_CreateMemBDev(&self) -> Arc; diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index da9db596..270a4d9a 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -298,6 +298,7 @@ dependencies = [ "spin 0.5.3", "syscalls", "unwind", + "virtio_backend_trusted", ] [[package]] @@ -340,6 +341,14 @@ dependencies = [ "syscalls", ] +[[package]] +name = "libtime" +version = "0.1.0" +dependencies = [ + "console", + "libsyscalls", +] + [[package]] name = "log" version = "0.4.11" @@ -349,6 +358,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "malloc" +version = "0.1.0" +dependencies = [ + "libsyscalls", + "slabmalloc 0.7.0", + "spin 0.5.3", +] + [[package]] name = "maybe-uninit" version = "2.0.0" @@ -538,10 +556,11 @@ dependencies = [ "platform", "rand", "signature", - "slabmalloc", + "slabmalloc 0.7.0 (git+https://github.com/gz/rust-slabmalloc.git)", "spin 0.5.3", "syscalls", "unwind", + "virtio_backend_trusted", "volatile", "x86 0.33.0", "x86_64", @@ -612,6 +631,13 @@ version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29f060a7d147e33490ec10da418795238fd7545bba241504d6b31a409f2e6210" +[[package]] +name = "slabmalloc" +version = "0.7.0" +dependencies = [ + "log", +] + [[package]] name = "slabmalloc" version = "0.7.0" @@ -710,12 +736,47 @@ dependencies = [ "syscalls", ] +[[package]] +name = "virtio_backend_trusted" +version = "0.1.0" +dependencies = [ + "console", + "hashbrown 0.7.2", + "libsyscalls", + "libtime", + "malloc", + "spin 0.5.3", + "virtio_device", + "volatile_accessor", +] + +[[package]] +name = "virtio_device" +version = "0.1.0" +dependencies = [ + "console", + "libsyscalls", + "libtime", + "malloc", + "volatile_accessor", +] + [[package]] name = "volatile" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6b06ad3ed06fef1713569d547cdbdb439eafed76341820fb0e0344f29a41945" +[[package]] +name = "volatile_accessor" +version = "0.1.0" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 6da421e4..e484dc45 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -47,6 +47,7 @@ interface = { path = "../interface/generated" } ahci = { path = "../lib/core/interfaces/dev/ahci" } platform = { path = "../lib/core/interfaces/platform" } # pci_driver = { path = "../lib/core/interfaces/dev/pci/pci_driver" } +virtio_backend_trusted = { path = "../lib/devices/virtio_backend" } [dependencies.lazy_static] version = "1.3.0" diff --git a/lib/devices/virtio_backend/Cargo.lock b/lib/devices/virtio_backend/Cargo.lock new file mode 100644 index 00000000..08a4fee9 --- /dev/null +++ b/lib/devices/virtio_backend/Cargo.lock @@ -0,0 +1,264 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ahash" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" + +[[package]] +name = "ahci" +version = "0.1.0" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console" +version = "0.1.0" +dependencies = [ + "libsyscalls", + "spin", +] + +[[package]] +name = "hashbrown" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf" +dependencies = [ + "ahash", + "autocfg", +] + +[[package]] +name = "interface" +version = "0.1.0" +dependencies = [ + "bitflags", + "byteorder", + "console", + "hashbrown", + "libsyscalls", + "num-derive", + "num-traits", + "pci_driver", + "spin", + "syscalls", + "unwind", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libsyscalls" +version = "0.1.0" +dependencies = [ + "pc-keyboard", + "platform", + "spin", + "syscalls", +] + +[[package]] +name = "libtime" +version = "0.1.0" +dependencies = [ + "console", + "libsyscalls", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "malloc" +version = "0.1.0" +dependencies = [ + "libsyscalls", + "slabmalloc", + "spin", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "pc-keyboard" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff50ab09ba31bcebc0669f4e64c0952fae1acdca9e6e0587e68e4e8443808ac" + +[[package]] +name = "pci_driver" +version = "0.1.0" +dependencies = [ + "ahci", + "platform", +] + +[[package]] +name = "platform" +version = "0.1.0" + +[[package]] +name = "proc-macro2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "protocol" +version = "0.1.0" +dependencies = [ + "bitfield", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "slabmalloc" +version = "0.7.0" +dependencies = [ + "log", +] + +[[package]] +name = "spin" +version = "0.5.3" + +[[package]] +name = "syn" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "syscalls" +version = "0.1.0" +dependencies = [ + "pc-keyboard", + "platform", + "protocol", + "spin", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "unwind" +version = "0.1.0" +dependencies = [ + "libsyscalls", + "syscalls", +] + +[[package]] +name = "virtio_device" +version = "0.1.0" +dependencies = [ + "console", + "libsyscalls", + "libtime", + "malloc", + "volatile_accessor", +] + +[[package]] +name = "virtio_network_device" +version = "0.1.0" +dependencies = [ + "console", + "hashbrown", + "interface", + "libsyscalls", + "libtime", + "malloc", + "pci_driver", + "spin", + "virtio_device", + "volatile_accessor", +] + +[[package]] +name = "volatile_accessor" +version = "0.1.0" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn", +] diff --git a/lib/devices/virtio_backend/Cargo.toml b/lib/devices/virtio_backend/Cargo.toml new file mode 100644 index 00000000..b59463aa --- /dev/null +++ b/lib/devices/virtio_backend/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "virtio_backend_trusted" +version = "0.1.0" +authors = ["Redleaf team "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +libsyscalls = { path = "../../../lib/core/libsyscalls" } +libtime = { path = "../../../lib/core/libtime" } +console = { path = "../../../lib/core/console" } +malloc = { path = "../../../lib/core/malloc" } +spin = { path = "../../../lib/core/spin-rs" } +volatile_accessor = { path = "../../../lib/external/volatile_accessor" } + + + +virtio_device = { path = "../virtio" } + +hashbrown = "0.7.2" \ No newline at end of file diff --git a/lib/devices/virtio_backend/src/defs.rs b/lib/devices/virtio_backend/src/defs.rs new file mode 100644 index 00000000..a2f95b98 --- /dev/null +++ b/lib/devices/virtio_backend/src/defs.rs @@ -0,0 +1,3 @@ +pub struct VirtioMMIOConfiguration { + pub configuration_address: usize, +} diff --git a/lib/devices/virtio_backend/src/lib.rs b/lib/devices/virtio_backend/src/lib.rs new file mode 100644 index 00000000..7b5d56ea --- /dev/null +++ b/lib/devices/virtio_backend/src/lib.rs @@ -0,0 +1,13 @@ +#![no_std] +#![no_main] +#![feature( + box_syntax, + const_fn, + const_raw_ptr_to_usize_cast, + const_in_array_repeat_expressions, + untagged_unions, + maybe_uninit_extra +)] + +pub mod defs; +extern crate alloc; diff --git a/lib/devices/virtio_backend/src/pci.rs b/lib/devices/virtio_backend/src/pci.rs new file mode 100644 index 00000000..2d35c0a6 --- /dev/null +++ b/lib/devices/virtio_backend/src/pci.rs @@ -0,0 +1,56 @@ +use console::println; +use pci_driver::DeviceBarRegions; + +use crate::VirtioNetInner; + +use alloc::boxed::Box; +use interface::net::Net; + +const VIRTIO_PCI_VID: u16 = 0x1af4; +const VIRTIO_PCI_DID: u16 = 0x1000; + +pub struct PciFactory { + mmio_base: Option, +} + +impl pci_driver::PciDriver for PciFactory { + fn probe(&mut self, bar_region: DeviceBarRegions) { + println!("VirtioNet PCI probe called"); + match bar_region { + DeviceBarRegions::Virtio(bar) => unsafe { + self.mmio_base = Some(bar.get_base() as usize); + }, + ty => { + println!("VirtioNet PCI probed with unsupported device {:?}", ty); + } + } + } + + /// Returns the Vendor ID for a VIRTIO Network Device + fn get_vid(&self) -> u16 { + VIRTIO_PCI_VID + } + + /// Returns the Device ID for a VIRTIO Network Device + fn get_did(&self) -> u16 { + // FIXME: Another possibility is the Transitional Device ID 0x1000 + VIRTIO_PCI_DID + } + + fn get_driver_type(&self) -> pci_driver::PciDrivers { + pci_driver::PciDrivers::VirtioDriver + } +} + +impl PciFactory { + pub fn new() -> Self { + Self { mmio_base: None } + } + + pub fn to_device(self) -> Option { + self.mmio_base.map(|base| { + let dev = unsafe { VirtioNetInner::new(base) }; + dev + }) + } +} diff --git a/lib/devices/virtio_net_mmio/Cargo.lock b/lib/devices/virtio_net_mmio/Cargo.lock new file mode 100644 index 00000000..08a4fee9 --- /dev/null +++ b/lib/devices/virtio_net_mmio/Cargo.lock @@ -0,0 +1,264 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ahash" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" + +[[package]] +name = "ahci" +version = "0.1.0" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console" +version = "0.1.0" +dependencies = [ + "libsyscalls", + "spin", +] + +[[package]] +name = "hashbrown" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf" +dependencies = [ + "ahash", + "autocfg", +] + +[[package]] +name = "interface" +version = "0.1.0" +dependencies = [ + "bitflags", + "byteorder", + "console", + "hashbrown", + "libsyscalls", + "num-derive", + "num-traits", + "pci_driver", + "spin", + "syscalls", + "unwind", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libsyscalls" +version = "0.1.0" +dependencies = [ + "pc-keyboard", + "platform", + "spin", + "syscalls", +] + +[[package]] +name = "libtime" +version = "0.1.0" +dependencies = [ + "console", + "libsyscalls", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "malloc" +version = "0.1.0" +dependencies = [ + "libsyscalls", + "slabmalloc", + "spin", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "pc-keyboard" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff50ab09ba31bcebc0669f4e64c0952fae1acdca9e6e0587e68e4e8443808ac" + +[[package]] +name = "pci_driver" +version = "0.1.0" +dependencies = [ + "ahci", + "platform", +] + +[[package]] +name = "platform" +version = "0.1.0" + +[[package]] +name = "proc-macro2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "protocol" +version = "0.1.0" +dependencies = [ + "bitfield", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "slabmalloc" +version = "0.7.0" +dependencies = [ + "log", +] + +[[package]] +name = "spin" +version = "0.5.3" + +[[package]] +name = "syn" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "syscalls" +version = "0.1.0" +dependencies = [ + "pc-keyboard", + "platform", + "protocol", + "spin", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "unwind" +version = "0.1.0" +dependencies = [ + "libsyscalls", + "syscalls", +] + +[[package]] +name = "virtio_device" +version = "0.1.0" +dependencies = [ + "console", + "libsyscalls", + "libtime", + "malloc", + "volatile_accessor", +] + +[[package]] +name = "virtio_network_device" +version = "0.1.0" +dependencies = [ + "console", + "hashbrown", + "interface", + "libsyscalls", + "libtime", + "malloc", + "pci_driver", + "spin", + "virtio_device", + "volatile_accessor", +] + +[[package]] +name = "volatile_accessor" +version = "0.1.0" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn", +] diff --git a/lib/devices/virtio_net_mmio/Cargo.toml b/lib/devices/virtio_net_mmio/Cargo.toml new file mode 100644 index 00000000..fe88f116 --- /dev/null +++ b/lib/devices/virtio_net_mmio/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "virtio_network_device" +version = "0.1.0" +authors = ["Redleaf team "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +libsyscalls = { path = "../../../lib/core/libsyscalls" } +libtime = { path = "../../../lib/core/libtime" } +console = { path = "../../../lib/core/console" } +malloc = { path = "../../../lib/core/malloc" } +spin = { path = "../../../lib/core/spin-rs" } +volatile_accessor = { path = "../../../lib/external/volatile_accessor" } + +pci_driver = { path = "../../../lib/core/interfaces/dev/pci/pci_driver" } +interface = { path = "../../../interface/generated" } + + +virtio_device = { path = "../virtio" } + +hashbrown = "0.7.2" \ No newline at end of file diff --git a/lib/devices/virtio_net_mmio/src/lib.rs b/lib/devices/virtio_net_mmio/src/lib.rs new file mode 100644 index 00000000..d930596b --- /dev/null +++ b/lib/devices/virtio_net_mmio/src/lib.rs @@ -0,0 +1,471 @@ +#![no_std] +#![no_main] +#![feature( + box_syntax, + const_fn, + const_raw_ptr_to_usize_cast, + const_in_array_repeat_expressions, + untagged_unions, + maybe_uninit_extra +)] + +pub mod pci; +extern crate alloc; + +use core::usize; + +use alloc::alloc::{alloc, Layout}; +use alloc::sync::Arc; +use alloc::vec; +use alloc::vec::Vec; +use console::println; +use hashbrown::HashMap; +use interface::rref::{RRef, RRefDeque}; +use spin::Mutex; +use virtio_device::defs::{ + VirtQueue, VirtqAvailable, VirtqAvailablePacked, VirtqDescriptor, VirtqUsed, VirtqUsedElement, + VirtqUsedPacked, +}; +use virtio_device::{Mmio, VirtioDeviceStatus}; + +#[repr(C, packed)] +pub struct VirtioNetworkDeviceConfig { + mac: [u8; 6], + status: u16, + // Not available without negotiating features VIRTIO_NET_F_MQ and VIRTIO_NET_F_MTU + // max_virtqueue_pairs: u16, + // mtu: u16, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct VirtioNetworkHeader { + pub flags: u8, + pub gso_type: u8, + pub header_length: u16, + pub gso_size: u16, + pub csum_start: u16, + pub csum_offset: u16, + // pub num_buffers: u16, +} + +struct VirtualQueues { + receive_queue: VirtQueue, + transmit_queue: VirtQueue, +} + +type NetworkPacketBuffer = [u8; 1514]; + +pub struct VirtioNetInner { + mmio: Mmio, + virtual_queues: Option, // None until init() is called + + /// This is the size of the queues used by the device, it is read during init(). + /// It would be less annoying to use if it were usize but it truly is a u16 value. + queue_size: u16, + + /// This tracks the maximum number of buffers or descriptor chains we can simultaneiously have. + /// For the network driver, each network packet requires two descriptors so this will be + /// queue_size / 2. + buffer_count: usize, + + /// Dummy VirtioNetHeaders. + /// The driver doesn't actually use these but they are required by the spec + virtio_network_headers: Vec, + + /// Tracks which descriptors on the queue are free + rx_free_descriptors: Vec, + /// Tracks which descriptors on the queue are free + tx_free_descriptors: Vec, + + /// The last index (of the used ring) that was checked by the driver + rx_last_idx: u16, + /// The last index (of the used ring) that was checked by the driver + tx_last_idx: u16, + + rx_buffers: Vec>>, + tx_buffers: Vec>>, +} + +impl VirtioNetInner { + /// Returns an initialized VirtioNet from a base address. + pub unsafe fn new(mmio_base: usize) -> Self { + Self { + mmio: Mmio::new(mmio_base), + + queue_size: 0, // We will update this (and the vecs) in init() + buffer_count: 0, + + virtual_queues: None, + + virtio_network_headers: vec![], + + rx_free_descriptors: vec![], + tx_free_descriptors: vec![], + + rx_buffers: vec![], + tx_buffers: vec![], + + rx_last_idx: 0, + tx_last_idx: 0, + } + } + + pub fn init(&mut self) { + println!("Initializing Virtio Network Device"); + + // VIRTIO DEVICE INIT + // https://docs.oasis-open.org/virtio/virtio/v1.1/cs01/virtio-v1.1-cs01.html#x1-920001 + // + // Reset the device. + // Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. + // Set the DRIVER status bit: the guest OS knows how to drive the device. + // Read device feature bits, and write the subset of feature bits understood by the OS and driver to the device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration fields to check that it can support the device before accepting it. + // Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. + // Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. + // Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup, reading and possibly writing the device’s virtio configuration space, and population of virtqueues. + // Set the DRIVER_OK status bit. At this point the device is “live”. + + // Reset the device + // Failing to do this DOES cause errors, don't ask how I know *sigh* + unsafe { + self.mmio.accessor.write_device_status(0); + } + Mmio::memory_fence(); + + // Acknowledge Device + unsafe { + self.mmio + .update_device_status(VirtioDeviceStatus::Acknowledge); + self.mmio.update_device_status(VirtioDeviceStatus::Driver); // But do we really know how to drive the device? + } + + self.negotiate_features(); + + // Tell the Device that feature Negotiation is complete + unsafe { + self.mmio + .update_device_status(VirtioDeviceStatus::FeaturesOk); + } + + // Check that Features OK Bit is still set! + // self.print_device_status(); + if (self.mmio.accessor.read_device_status() & VirtioDeviceStatus::FeaturesOk.value()) == 0 { + panic!("Failed to negotiate Virtio Net features!"); + } + + // Read the queue size + // This value is that largest possible queue size so we will use it to initialize all of our vectors + let queue_size = self.mmio.accessor.read_queue_size(); + if queue_size == 0 { + panic!("ERROR: VIRTIO NET: BAD QUEUE SIZE!"); + } + + self.queue_size = queue_size; + self.buffer_count = (self.queue_size / 2) as usize; // Each buffer requires two descriptors + + unsafe { + self.setup_virtual_queues(); + } + + self.initialize_vectors(); + + // Setup Virtual Queues + self.initialize_virtual_queue(0, &(self.virtual_queues.as_ref().unwrap().receive_queue)); + + // println!("Virtio Net Should Yield here!"); + // self.print_device_config(); + // libsyscalls::syscalls::sys_yield(); + + self.initialize_virtual_queue(1, &(self.virtual_queues.as_ref().unwrap().transmit_queue)); + + // Tell the Device we're all done, even though we aren't + unsafe { self.mmio.update_device_status(VirtioDeviceStatus::DriverOk) }; + + // self.print_device_status(); + + // self.mmio.accessor.write_queue_select(0); + // self.print_device_config(); + // self.mmio.accessor.write_queue_select(1); + // self.print_device_config(); + + println!("VIRTIO NET READY!"); + } + + /// Negotiates Virtio Driver Features + fn negotiate_features(&mut self) { + let mut driver_features: u32 = 0; + driver_features |= 1 << 5; // Enable Device MAC Address + driver_features |= 1 << 16; // Enable Device Status + + self.mmio.accessor.write_driver_feature(driver_features); // Should be &'d with device_features + } + + pub fn print_device_config(&mut self) { + let mut cfg = unsafe { self.mmio.read_common_config() }; + println!("{:#?}", cfg); + } + + pub fn print_device_status(&mut self) { + let device_status = self.mmio.accessor.read_device_status(); + println!("Device Status Bits: {:b}", device_status); + } + + /// Initializes all the vectors using the set buffer_count + fn initialize_vectors(&mut self) { + self.virtio_network_headers = vec![ + VirtioNetworkHeader { + csum_offset: 0, + csum_start: 0, + flags: 0, + gso_size: 0, + gso_type: 0, + header_length: 0, + }; + self.buffer_count + ]; + + self.rx_free_descriptors = vec![true; self.buffer_count]; + self.tx_free_descriptors = vec![true; self.buffer_count]; + + self.rx_buffers = Vec::with_capacity(self.buffer_count); + self.rx_buffers.resize_with(self.buffer_count, || None); + self.tx_buffers = Vec::with_capacity(self.buffer_count); + self.tx_buffers.resize_with(self.buffer_count, || None); + } + + unsafe fn setup_virtual_queues(&mut self) { + self.virtual_queues = Some(VirtualQueues { + receive_queue: VirtQueue { + descriptors: vec![VirtqDescriptor::default(); self.queue_size as usize], + available: VirtqAvailable::new(self.queue_size), + used: VirtqUsed::new(self.queue_size), + }, + transmit_queue: VirtQueue { + descriptors: vec![VirtqDescriptor::default(); self.queue_size as usize], + available: VirtqAvailable::new(self.queue_size), + used: VirtqUsed::new(self.queue_size), + }, + }); + } + + /// Receive Queues must be 2*N and Transmit Queues must be 2*N + 1 + /// For example, Receive Queue must be 0 and Transmit Queue must be 1 + fn initialize_virtual_queue(&self, queue_index: u16, virt_queue: &VirtQueue) { + self.mmio.accessor.write_queue_select(queue_index); + + self.mmio + .accessor + .write_queue_desc(virt_queue.descriptors.as_ptr() as u64); + self.mmio.accessor.write_queue_driver( + (virt_queue.available.data.as_ref() as *const VirtqAvailablePacked) as u64, + ); + self.mmio + .accessor + .write_queue_device((virt_queue.used.data.as_ref() as *const VirtqUsedPacked) as u64); + self.mmio.accessor.write_queue_enable(1); + } + + /// Returns a free descriptor chain index + /// For Virtio Net, the VirtioNetworkHeader is placed at i and the Packet Buffer will be placed at i + self.buffer_count + fn get_free_idx(free_buffers: &mut Vec) -> Result { + for i in 0..free_buffers.len() { + if free_buffers[i] { + free_buffers[i] = false; + return Ok(i); + } + } + + return Err(()); + } + + #[inline] + fn get_addr(obj: &T) -> u64 { + (obj as *const T) as u64 + } + + /// If the buffer can't be added, it is returned in the Err() + fn add_rx_buffer( + &mut self, + buffer: RRef, + ) -> Result<(), RRef> { + let rx_q = &mut self.virtual_queues.as_mut().unwrap().receive_queue; + + if let Ok(header_idx) = Self::get_free_idx(&mut self.rx_free_descriptors) { + let buffer_idx = header_idx + self.buffer_count; + let buffer_addr = buffer.as_ptr() as u64; + + // Store it so it isn't dropped + self.rx_buffers[header_idx] = Some(buffer); + + // One descriptor points at the network header, chain this with a descriptor to the buffer + // Header + rx_q.descriptors[header_idx] = VirtqDescriptor { + addr: Self::get_addr(&self.virtio_network_headers[header_idx]), + len: core::mem::size_of::() as u32, // 10 bytes + // 1 is NEXT FLAG + // 2 is WRITABLE FLAG + flags: 1 | 2, + next: buffer_idx as u16, + }; + // Actual Buffer + rx_q.descriptors[buffer_idx] = VirtqDescriptor { + addr: buffer_addr, + len: 1514, + flags: 2, + next: 0, + }; + + // Mark the buffer as usable + *rx_q + .available + .ring(rx_q.available.data.idx % self.queue_size) = header_idx as u16; + rx_q.available.data.idx = rx_q.available.data.idx.wrapping_add(1); // We only added one "chain head" + + unsafe { + self.mmio.queue_notify(0, 0); + } + + return Ok(()); + } else { + return Err(buffer); + } + } + + pub fn add_rx_buffers( + &mut self, + packets: &mut RRefDeque, + collect: &mut RRefDeque, + ) { + if packets.len() == 0 { + return; + } + + while let Some(buffer) = packets.pop_front() { + let res = self.add_rx_buffer(buffer); + + if res.is_err() { + packets.push_back(res.unwrap_err()); + break; + } + } + } + + /// Returns an error if there's no free space in the TX queue, Ok otherwise + fn add_tx_packet( + &mut self, + buffer: RRef, + ) -> Result<(), RRef> { + let tx_q = &mut self.virtual_queues.as_mut().unwrap().transmit_queue; + + if let Ok(header_idx) = Self::get_free_idx(&mut self.tx_free_descriptors) { + let buffer_idx = header_idx + self.buffer_count; + let buffer_addr = buffer.as_ptr() as u64; + + // Store it so it isn't dropped + self.tx_buffers[header_idx] = Some(buffer); + + tx_q.descriptors[header_idx] = VirtqDescriptor { + addr: Self::get_addr(&self.virtio_network_headers[header_idx]), + len: core::mem::size_of::() as u32, // 10 bytes + flags: 1, // 1 is next flag + next: buffer_idx as u16, + }; + tx_q.descriptors[buffer_idx] = VirtqDescriptor { + addr: buffer_addr, + len: 1514, + flags: 0, + next: 0, + }; + + *tx_q + .available + .ring(tx_q.available.data.idx % self.queue_size) = header_idx as u16; + tx_q.available.data.idx = tx_q.available.data.idx.wrapping_add(1); + + unsafe { + self.mmio.queue_notify(1, 1); + } + return Ok(()); + } else { + return Err(buffer); + } + } + + pub fn add_tx_buffers(&mut self, packets: &mut RRefDeque) { + if packets.len() == 0 { + return; + } + + while let Some(packet) = packets.pop_front() { + let res = self.add_tx_packet(packet); + + if res.is_err() { + println!("ERROR: VIRTIO NET: COULD NOT ADD TX PACKET. NO FREE SPACE!"); + packets.push_back(res.unwrap_err()); + break; + } + } + } + + /// Adds new packets to `packets`. Returns the number of received packets + /// Returns the number of new packets found + pub fn get_received_packets( + &mut self, + collect: &mut RRefDeque, + ) -> usize { + /// We have to return the number of packets received + let mut new_packets_count = 0; + let rx_q = &mut self.virtual_queues.as_mut().unwrap().receive_queue; + + while self.rx_last_idx != rx_q.used.data.idx { + let used_element = rx_q.used.ring(self.rx_last_idx % self.queue_size); + let header_descriptor = &rx_q.descriptors[used_element.id as usize]; + let buffer_descriptor = &rx_q.descriptors[header_descriptor.next as usize]; + + if let Some(buffer) = self.rx_buffers[used_element.id as usize].take() { + // Processed packets are "collected" + collect.push_back(buffer); + new_packets_count += 1; + + // Free the descriptor + self.rx_free_descriptors[used_element.id as usize] = true; + } else { + println!("ERROR: VIRTIO NET: RX BUFFER MISSING"); + } + + self.rx_last_idx = self.rx_last_idx.wrapping_add(1); + } + + new_packets_count + } + + /// Returns the number of tx packets that have been sent + pub fn free_processed_tx_packets( + &mut self, + packets: &mut RRefDeque, + ) -> usize { + let mut freed_count = 0; + let tx_q = &mut self.virtual_queues.as_mut().unwrap().transmit_queue; + + while self.tx_last_idx != tx_q.used.data.idx { + let used_element = tx_q.used.ring(self.tx_last_idx % self.queue_size); + let header_descriptor = &tx_q.descriptors[used_element.id as usize]; + let buffer_descriptor = &tx_q.descriptors[header_descriptor.next as usize]; + + if let Some(buffer) = self.tx_buffers[used_element.id as usize].take() { + packets.push_back(buffer); + freed_count += 1; + + // Free the descriptor + self.tx_free_descriptors[used_element.id as usize] = true; + } else { + println!("ERROR: VIRTIO NET: TX BUFFER MISSING"); + } + + self.tx_last_idx = self.tx_last_idx.wrapping_add(1); + } + + freed_count + } +} diff --git a/lib/devices/virtio_net_mmio/src/pci.rs b/lib/devices/virtio_net_mmio/src/pci.rs new file mode 100644 index 00000000..2d35c0a6 --- /dev/null +++ b/lib/devices/virtio_net_mmio/src/pci.rs @@ -0,0 +1,56 @@ +use console::println; +use pci_driver::DeviceBarRegions; + +use crate::VirtioNetInner; + +use alloc::boxed::Box; +use interface::net::Net; + +const VIRTIO_PCI_VID: u16 = 0x1af4; +const VIRTIO_PCI_DID: u16 = 0x1000; + +pub struct PciFactory { + mmio_base: Option, +} + +impl pci_driver::PciDriver for PciFactory { + fn probe(&mut self, bar_region: DeviceBarRegions) { + println!("VirtioNet PCI probe called"); + match bar_region { + DeviceBarRegions::Virtio(bar) => unsafe { + self.mmio_base = Some(bar.get_base() as usize); + }, + ty => { + println!("VirtioNet PCI probed with unsupported device {:?}", ty); + } + } + } + + /// Returns the Vendor ID for a VIRTIO Network Device + fn get_vid(&self) -> u16 { + VIRTIO_PCI_VID + } + + /// Returns the Device ID for a VIRTIO Network Device + fn get_did(&self) -> u16 { + // FIXME: Another possibility is the Transitional Device ID 0x1000 + VIRTIO_PCI_DID + } + + fn get_driver_type(&self) -> pci_driver::PciDrivers { + pci_driver::PciDrivers::VirtioDriver + } +} + +impl PciFactory { + pub fn new() -> Self { + Self { mmio_base: None } + } + + pub fn to_device(self) -> Option { + self.mmio_base.map(|base| { + let dev = unsafe { VirtioNetInner::new(base) }; + dev + }) + } +} diff --git a/lib/external/volatile_accessor/src/lib.rs b/lib/external/volatile_accessor/src/lib.rs index c286b9c5..e1d10cb8 100644 --- a/lib/external/volatile_accessor/src/lib.rs +++ b/lib/external/volatile_accessor/src/lib.rs @@ -1,14 +1,14 @@ #![feature(log_syntax, proc_macro_def_site)] use core::panic; -use std::collections::HashMap; use quote::{format_ident, quote}; +use std::collections::HashMap; use lazy_static::lazy_static; use proc_macro::{Ident, TokenStream}; -use syn::{ImplItem, ImplItemMethod, ItemStruct, parse_quote}; +use syn::{parse_quote, ImplItem, ImplItemMethod, ItemStruct}; -lazy_static!( +lazy_static! { static ref SIZE_MAP: HashMap<&'static str, usize> = vec![ ("u8", 1), ("u16", 2), @@ -18,18 +18,25 @@ lazy_static!( ("i16", 2), ("i32", 4), ("i64", 8), + ] + .into_iter() + .collect(); +} - ].into_iter().collect(); -); - -/// Generate a +/// Generate a #[proc_macro_attribute] pub fn volatile_accessor(attr: TokenStream, item: TokenStream) -> TokenStream { // Parse the input tokens into a syntax tree assert!(attr.is_empty(), &attr.to_string()); - let st: ItemStruct = syn::parse(item).expect("interface definition must be a valid struct definition"); + let st: ItemStruct = + syn::parse(item).expect("interface definition must be a valid struct definition"); - assert_eq!(st.generics.params.len(), 0, "Generic is not supported: {:?}", st); + assert_eq!( + st.generics.params.len(), + 0, + "Generic is not supported: {:?}", + st + ); let mut offset: usize = 0; let mut accessor_impls: Vec = vec![]; @@ -49,18 +56,28 @@ pub fn volatile_accessor(attr: TokenStream, item: TokenStream) -> TokenStream { syn::Type::TraitObject(x) => unimplemented!("{:?}", x), syn::Type::Tuple(x) => unimplemented!("{:?}", x), syn::Type::Verbatim(x) => unimplemented!("{:?}", x), - syn::Type::__Nonexhaustive => unimplemented!(), syn::Type::Path(path) => { - let field_ident = field.ident.as_ref().expect(&format!("All field must be named: {:?}", st)); + let field_ident = field + .ident + .as_ref() + .expect(&format!("All field must be named: {:?}", st)); let field_type = &field.ty; - let path = path.path.segments.iter().map(|seg| seg.ident.to_string()).collect::>().join("::"); - let size = SIZE_MAP.get(path.as_str()).expect(&format!("Type {} not supported. Supported types are {:?}", path, *SIZE_MAP)); + let path = path + .path + .segments + .iter() + .map(|seg| seg.ident.to_string()) + .collect::>() + .join("::"); + let size = SIZE_MAP.get(path.as_str()).expect(&format!( + "Type {} not supported. Supported types are {:?}", + path, *SIZE_MAP + )); let read_accessor_ident = format_ident!("read_{}", &field_ident); let write_accessor_ident = format_ident!("write_{}", &field_ident); let offset_accessor_ident = format_ident!("{}_offset", &field_ident); let address_accessor_ident = format_ident!("{}_address", &field_ident); - // // Generate accessors. accessor_impls.push(parse_quote! { pub fn #offset_accessor_ident(&self) -> usize { @@ -84,11 +101,11 @@ pub fn volatile_accessor(attr: TokenStream, item: TokenStream) -> TokenStream { }); offset += size; - }, + } + _ => unimplemented!(), } } - let accessor_ident = format_ident!("{}VolatileAccessor", st.ident); let vis = &st.vis; TokenStream::from(quote! { @@ -96,7 +113,7 @@ pub fn volatile_accessor(attr: TokenStream, item: TokenStream) -> TokenStream { #[allow(dead_code)] #vis struct #accessor_ident { - base: usize, + base: usize, } #[allow(dead_code)] diff --git a/tools/rv6-mkfs/Cargo.lock b/tools/rv6-mkfs/Cargo.lock index 7102abc6..92c7575d 100644 --- a/tools/rv6-mkfs/Cargo.lock +++ b/tools/rv6-mkfs/Cargo.lock @@ -34,6 +34,12 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "console" version = "0.1.0" @@ -67,8 +73,15 @@ dependencies = [ "spin", "syscalls", "unwind", + "virtio_backend_trusted", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libsyscalls" version = "0.1.0" @@ -79,6 +92,32 @@ dependencies = [ "syscalls", ] +[[package]] +name = "libtime" +version = "0.1.0" +dependencies = [ + "console", + "libsyscalls", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "malloc" +version = "0.1.0" +dependencies = [ + "libsyscalls", + "slabmalloc", + "spin", +] + [[package]] name = "num-derive" version = "0.3.3" @@ -152,6 +191,13 @@ dependencies = [ "num-traits", ] +[[package]] +name = "slabmalloc" +version = "0.7.0" +dependencies = [ + "log", +] + [[package]] name = "spin" version = "0.5.3" @@ -190,3 +236,38 @@ dependencies = [ "libsyscalls", "syscalls", ] + +[[package]] +name = "virtio_backend_trusted" +version = "0.1.0" +dependencies = [ + "console", + "hashbrown", + "libsyscalls", + "libtime", + "malloc", + "spin", + "virtio_device", + "volatile_accessor", +] + +[[package]] +name = "virtio_device" +version = "0.1.0" +dependencies = [ + "console", + "libsyscalls", + "libtime", + "malloc", + "volatile_accessor", +] + +[[package]] +name = "volatile_accessor" +version = "0.1.0" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn", +] From b19bbfefbb1a7bb2c494252f07e4d35aa0f2cbd5 Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Sun, 29 Aug 2021 21:38:01 -0700 Subject: [PATCH 06/15] Added double domain design --- domains/Cargo.lock | 20 +- domains/sys/driver/virtio_backend/Cargo.toml | 3 + domains/sys/driver/virtio_backend/src/main.rs | 191 +++---- domains/sys/driver/virtio_backend/src/pci.rs | 56 --- .../driver/virtio_backend/src/virtio_net.rs | 473 ------------------ domains/sys/driver/virtio_net_mmio/Cargo.toml | 2 +- .../sys/driver/virtio_net_mmio/src/main.rs | 52 +- .../driver/virtio_net_mmio/src/virtio_net.rs | 473 ------------------ lib/devices/virtio_net_mmio/Cargo.toml | 2 +- lib/devices/virtio_net_mmio/src/lib.rs | 31 +- 10 files changed, 144 insertions(+), 1159 deletions(-) delete mode 100644 domains/sys/driver/virtio_backend/src/pci.rs delete mode 100644 domains/sys/driver/virtio_backend/src/virtio_net.rs delete mode 100644 domains/sys/driver/virtio_net_mmio/src/virtio_net.rs diff --git a/domains/Cargo.lock b/domains/Cargo.lock index 203dafbc..c4b3908c 100644 --- a/domains/Cargo.lock +++ b/domains/Cargo.lock @@ -1014,6 +1014,8 @@ dependencies = [ "spin 0.5.3", "syscalls", "virtio_device", + "virtio_net_mmio", + "virtio_net_mmio_device", ] [[package]] @@ -1117,7 +1119,23 @@ dependencies = [ "spin 0.5.3", "syscalls", "virtio_device", - "virtio_network_device", + "virtio_net_mmio_device", +] + +[[package]] +name = "virtio_net_mmio_device" +version = "0.1.0" +dependencies = [ + "console", + "hashbrown 0.7.2", + "interface", + "libsyscalls", + "libtime", + "malloc", + "pci_driver", + "spin 0.5.3", + "virtio_device", + "volatile_accessor", ] [[package]] diff --git a/domains/sys/driver/virtio_backend/Cargo.toml b/domains/sys/driver/virtio_backend/Cargo.toml index 271f0a29..db3c2ab3 100644 --- a/domains/sys/driver/virtio_backend/Cargo.toml +++ b/domains/sys/driver/virtio_backend/Cargo.toml @@ -18,6 +18,9 @@ protocol = { path = "../../../../lib/core/interfaces/protocol" } platform = { path = "../../../../lib/core/interfaces/platform" } interface = { path = "../../../../interface/generated" } +virtio_net_mmio_device = { path = "../../../../lib/devices/virtio_net_mmio" } +virtio_net_mmio = { path = "../virtio_net_mmio" } + virtio_device = { path = "../../../../lib/devices/virtio" } [features] diff --git a/domains/sys/driver/virtio_backend/src/main.rs b/domains/sys/driver/virtio_backend/src/main.rs index 7e87d5b8..a869731b 100644 --- a/domains/sys/driver/virtio_backend/src/main.rs +++ b/domains/sys/driver/virtio_backend/src/main.rs @@ -6,139 +6,115 @@ const_raw_ptr_to_usize_cast, const_in_array_repeat_expressions, untagged_unions, - maybe_uninit_extra + maybe_uninit_extra, + core_intrinsics )] extern crate alloc; extern crate malloc; mod defs; -mod virtio_net; -use crate::{ - defs::{VirtioBackendQueue, MAX_SUPPORTED_QUEUES}, - virtio_net::VirtioNetInner, -}; +use crate::defs::{VirtioBackendQueue, MAX_SUPPORTED_QUEUES}; use alloc::{boxed::Box, sync::Arc, vec, vec::Vec}; use console::println; use core::{ - borrow::{Borrow, BorrowMut}, + intrinsics::size_of, panic::PanicInfo, + ptr::{read_volatile, write_volatile}, }; use libsyscalls::syscalls::{sys_backtrace, sys_create_thread, sys_yield}; +use libtime::sys_ns_sleep; use spin::{Mutex, MutexGuard, Once}; use syscalls::{Heap, Syscall}; use virtio_device::VirtioPciCommonConfig; +use virtio_net_mmio_device::VirtioNetworkDeviceConfig; + +/// Increment this counter whenever you wish to notify the device +const DEVICE_NOTIFY: *mut usize = (0x100000 - size_of::()) as *mut usize; + +const MMIO_ADDRESS: *mut VirtioPciCommonConfig = 0x100000 as *mut VirtioPciCommonConfig; struct VirtioBackendInner { device_config: VirtioPciCommonConfig, backend_queues: Vec>, } -struct VirtioBackend(Once>>); - -impl VirtioBackend { - pub const fn new() -> Self { - VirtioBackend(Once::new()) - } - - pub fn init(&mut self) { - self.0.call_once(|| { - Arc::new(Mutex::new(VirtioBackendInner { - device_config: VirtioPciCommonConfig { - device_feature_select: 0, - device_feature: 0, - driver_feature_select: 0, - driver_feature: 0, - msix_config: 0, - num_queues: MAX_SUPPORTED_QUEUES, - device_status: 0, - config_generation: 0, - queue_select: 0, - queue_size: 256, - queue_msix_vector: 0, - queue_enable: 0, - queue_notify_off: 0, - queue_desc: 0, - queue_driver: 0, - queue_device: 0, - }, - backend_queues: vec![None, None, None], - })) - }); - } - - pub fn lock(&mut self) -> MutexGuard { - self.0.wait().unwrap().lock() - } -} - -static mut VIRTIO_BACKEND: VirtioBackend = VirtioBackend::new(); - /// Call this function anytime the frontend modifies device config and backend needs to update -pub fn virtio_device_config_modified() { - let mut backend = unsafe { VIRTIO_BACKEND.borrow_mut().lock() }; - +// pub fn virtio_device_config_modified() { +// let mut backend = unsafe { VIRTIO_BACKEND.borrow_mut().lock() }; + +// unsafe { +// // Update the backend's info on the queues +// if backend.device_config.queue_enable == 1 { +// if backend.device_config.queue_select >= MAX_SUPPORTED_QUEUES { +// panic!("Virtio Backend Supports at most {} queues but the device has a queue at index {}", +// MAX_SUPPORTED_QUEUES, +// backend.device_config.queue_select); +// } else { +// // Update the queue information +// let queue = VirtioBackendQueue { +// queue_index: backend.device_config.queue_select, +// queue_enable: true, +// queue_size: backend.device_config.queue_size, +// queue_descriptor: backend.device_config.queue_desc, +// queue_device: backend.device_config.queue_device, +// queue_driver: backend.device_config.queue_driver, + +// device_idx: 0, +// driver_idx: 0, +// }; + +// let index = queue.queue_index; +// backend.backend_queues[index as usize] = Some(queue); +// } +// } + +// println!( +// "virtio_device_config_modified {:#?}", +// &backend.backend_queues +// ); +// } +// } + +extern "C" fn virtio_backend() { + // Initialize the device config unsafe { - // Update the backend's info on the queues - if backend.device_config.queue_enable == 1 { - if backend.device_config.queue_select >= MAX_SUPPORTED_QUEUES { - panic!("Virtio Backend Supports at most {} queues but the device has a queue at index {}", - MAX_SUPPORTED_QUEUES, - backend.device_config.queue_select); - } else { - // Update the queue information - let queue = VirtioBackendQueue { - queue_index: backend.device_config.queue_select, - queue_enable: true, - queue_size: backend.device_config.queue_size, - queue_descriptor: backend.device_config.queue_desc, - queue_device: backend.device_config.queue_device, - queue_driver: backend.device_config.queue_driver, - - device_idx: 0, - driver_idx: 0, - }; - - let index = queue.queue_index; - backend.backend_queues[index as usize] = Some(queue); - } - } - - println!( - "virtio_device_config_modified {:#?}", - &backend.backend_queues + write_volatile(DEVICE_NOTIFY, 0); + + write_volatile( + MMIO_ADDRESS, + VirtioPciCommonConfig { + device_feature_select: 0, + device_feature: 0, + driver_feature_select: 0, + driver_feature: 0, + msix_config: 0, + num_queues: MAX_SUPPORTED_QUEUES, + device_status: 0, + config_generation: 0, + queue_select: 0, + queue_size: 256, + queue_msix_vector: 0, + queue_enable: 0, + queue_notify_off: 0, + queue_desc: 0, + queue_driver: 0, + queue_device: 0, + }, ); } -} - -extern "C" fn virtio_frontend() { - let backend = unsafe { VIRTIO_BACKEND.borrow_mut() }; - - unsafe { - let mut VirtioInner = VirtioNetInner::new( - &backend.lock().device_config as *const VirtioPciCommonConfig as usize, - ); - - VirtioInner.init(); - } -} - -fn virtio_backend() { - let backend = unsafe { VIRTIO_BACKEND.borrow_mut() }; loop { - println!("{:#?}", backend.lock().device_config); - println!("{:#?}", backend.lock().backend_queues); - - for q in &mut backend.lock().backend_queues { - if let Some(queue) = q.as_mut() { - println!("Driver Queue: {:#?}", queue.get_driver_queue()); - println!("Device Queue: {:#?}", queue.get_device_queue()); - + // println!("Virtio Backend!"); + unsafe { + let dn = read_volatile(DEVICE_NOTIFY); + // println!("DEVICE_NOTIFY: {:#?}", &dn); + + if dn != 0 { + println!("{:#?}", read_volatile(MMIO_ADDRESS)); + write_volatile(DEVICE_NOTIFY, 0); } } - - println!("Virtio Backend Yield"); sys_yield(); } } @@ -148,12 +124,7 @@ pub fn trusted_entry(s: Box, heap: Box, -} - -impl pci_driver::PciDriver for PciFactory { - fn probe(&mut self, bar_region: DeviceBarRegions) { - println!("VirtioNet PCI probe called"); - match bar_region { - DeviceBarRegions::Virtio(bar) => unsafe { - self.mmio_base = Some(bar.get_base() as usize); - }, - ty => { - println!("VirtioNet PCI probed with unsupported device {:?}", ty); - } - } - } - - /// Returns the Vendor ID for a VIRTIO Network Device - fn get_vid(&self) -> u16 { - VIRTIO_PCI_VID - } - - /// Returns the Device ID for a VIRTIO Network Device - fn get_did(&self) -> u16 { - // FIXME: Another possibility is the Transitional Device ID 0x1000 - VIRTIO_PCI_DID - } - - fn get_driver_type(&self) -> pci_driver::PciDrivers { - pci_driver::PciDrivers::VirtioDriver - } -} - -impl PciFactory { - pub fn new() -> Self { - Self { mmio_base: None } - } - - pub fn to_device(self) -> Option { - self.mmio_base.map(|base| { - let dev = unsafe { VirtioNetInner::new(base) }; - dev - }) - } -} diff --git a/domains/sys/driver/virtio_backend/src/virtio_net.rs b/domains/sys/driver/virtio_backend/src/virtio_net.rs deleted file mode 100644 index ea6b3a84..00000000 --- a/domains/sys/driver/virtio_backend/src/virtio_net.rs +++ /dev/null @@ -1,473 +0,0 @@ -#![no_std] -#![no_main] -#![feature( - box_syntax, - const_fn, - const_raw_ptr_to_usize_cast, - const_in_array_repeat_expressions, - untagged_unions, - maybe_uninit_extra -)] - -extern crate alloc; - -use core::usize; - -use alloc::alloc::{alloc, Layout}; -use alloc::sync::Arc; -use alloc::vec; -use alloc::vec::Vec; -use console::println; -use interface::rref::{RRef, RRefDeque}; -use spin::Mutex; -use virtio_device::defs::{ - VirtQueue, VirtqAvailable, VirtqAvailablePacked, VirtqDescriptor, VirtqUsed, VirtqUsedElement, - VirtqUsedPacked, -}; -use virtio_device::{Mmio, VirtioDeviceStatus}; - -use crate::virtio_device_config_modified; - -#[repr(C, packed)] -pub struct VirtioNetworkDeviceConfig { - mac: [u8; 6], - status: u16, - // Not available without negotiating features VIRTIO_NET_F_MQ and VIRTIO_NET_F_MTU - // max_virtqueue_pairs: u16, - // mtu: u16, -} - -#[derive(Debug, Clone, Copy)] -#[repr(C, packed)] -pub struct VirtioNetworkHeader { - pub flags: u8, - pub gso_type: u8, - pub header_length: u16, - pub gso_size: u16, - pub csum_start: u16, - pub csum_offset: u16, - // pub num_buffers: u16, -} - -struct VirtualQueues { - receive_queue: VirtQueue, - transmit_queue: VirtQueue, -} - -type NetworkPacketBuffer = [u8; 1514]; - -pub struct VirtioNetInner { - mmio: Mmio, - virtual_queues: Option, // None until init() is called - - /// This is the size of the queues used by the device, it is read during init(). - /// It would be less annoying to use if it were usize but it truly is a u16 value. - queue_size: u16, - - /// This tracks the maximum number of buffers or descriptor chains we can simultaneiously have. - /// For the network driver, each network packet requires two descriptors so this will be - /// queue_size / 2. - buffer_count: usize, - - /// Dummy VirtioNetHeaders. - /// The driver doesn't actually use these but they are required by the spec - virtio_network_headers: Vec, - - /// Tracks which descriptors on the queue are free - rx_free_descriptors: Vec, - /// Tracks which descriptors on the queue are free - tx_free_descriptors: Vec, - - /// The last index (of the used ring) that was checked by the driver - rx_last_idx: u16, - /// The last index (of the used ring) that was checked by the driver - tx_last_idx: u16, - - rx_buffers: Vec>>, - tx_buffers: Vec>>, -} - -impl VirtioNetInner { - /// Returns an initialized VirtioNet from a base address. - pub unsafe fn new(mmio_base: usize) -> Self { - Self { - mmio: Mmio::new(mmio_base), - - queue_size: 0, // We will update this (and the vecs) in init() - buffer_count: 0, - - virtual_queues: None, - - virtio_network_headers: vec![], - - rx_free_descriptors: vec![], - tx_free_descriptors: vec![], - - rx_buffers: vec![], - tx_buffers: vec![], - - rx_last_idx: 0, - tx_last_idx: 0, - } - } - - pub fn init(&mut self) { - println!("Initializing Virtio Network Device"); - - // VIRTIO DEVICE INIT - // https://docs.oasis-open.org/virtio/virtio/v1.1/cs01/virtio-v1.1-cs01.html#x1-920001 - // - // Reset the device. - // Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. - // Set the DRIVER status bit: the guest OS knows how to drive the device. - // Read device feature bits, and write the subset of feature bits understood by the OS and driver to the device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration fields to check that it can support the device before accepting it. - // Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. - // Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. - // Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup, reading and possibly writing the device’s virtio configuration space, and population of virtqueues. - // Set the DRIVER_OK status bit. At this point the device is “live”. - - // Reset the device - // Failing to do this DOES cause errors, don't ask how I know *sigh* - self.mmio.accessor.write_device_status(0); - Mmio::memory_fence(); - - // Acknowledge Device - unsafe { - self.mmio - .update_device_status(VirtioDeviceStatus::Acknowledge); - self.mmio.update_device_status(VirtioDeviceStatus::Driver); // But do we really know how to drive the device? - } - - self.negotiate_features(); - - // Tell the Device that feature Negotiation is complete - unsafe { - self.mmio - .update_device_status(VirtioDeviceStatus::FeaturesOk); - } - - // Check that Features OK Bit is still set! - // self.print_device_status(); - if (self.mmio.accessor.read_device_status() & VirtioDeviceStatus::FeaturesOk.value()) == 0 { - panic!("Failed to negotiate Virtio Net features!"); - } - - // Read the queue size - // This value is that largest possible queue size so we will use it to initialize all of our vectors - let queue_size = self.mmio.accessor.read_queue_size(); - if queue_size == 0 { - panic!("ERROR: VIRTIO NET: BAD QUEUE SIZE!"); - } - - self.queue_size = queue_size; - self.buffer_count = (self.queue_size / 2) as usize; // Each buffer requires two descriptors - - unsafe { - self.setup_virtual_queues(); - } - - self.initialize_vectors(); - - // Setup Virtual Queues - self.initialize_virtual_queue(0, &(self.virtual_queues.as_ref().unwrap().receive_queue)); - - // println!("Virtio Net Should Yield here!"); - // self.print_device_config(); - // libsyscalls::syscalls::sys_yield(); - - virtio_device_config_modified(); - - self.initialize_virtual_queue(1, &(self.virtual_queues.as_ref().unwrap().transmit_queue)); - - virtio_device_config_modified(); - - // Tell the Device we're all done, even though we aren't - unsafe { self.mmio.update_device_status(VirtioDeviceStatus::DriverOk) }; - - // self.print_device_status(); - - // self.mmio.accessor.write_queue_select(0); - // self.print_device_config(); - // self.mmio.accessor.write_queue_select(1); - // self.print_device_config(); - - println!("VIRTIO NET READY!"); - } - - /// Negotiates Virtio Driver Features - fn negotiate_features(&mut self) { - let mut driver_features: u32 = 0; - driver_features |= 1 << 5; // Enable Device MAC Address - driver_features |= 1 << 16; // Enable Device Status - - self.mmio.accessor.write_driver_feature(driver_features); // Should be &'d with device_features - } - - pub fn print_device_config(&mut self) { - let mut cfg = unsafe { self.mmio.read_common_config() }; - println!("{:#?}", cfg); - } - - pub fn print_device_status(&mut self) { - let device_status = self.mmio.accessor.read_device_status(); - println!("Device Status Bits: {:b}", device_status); - } - - /// Initializes all the vectors using the set buffer_count - fn initialize_vectors(&mut self) { - self.virtio_network_headers = vec![ - VirtioNetworkHeader { - csum_offset: 0, - csum_start: 0, - flags: 0, - gso_size: 0, - gso_type: 0, - header_length: 0, - }; - self.buffer_count - ]; - - self.rx_free_descriptors = vec![true; self.buffer_count]; - self.tx_free_descriptors = vec![true; self.buffer_count]; - - self.rx_buffers = Vec::with_capacity(self.buffer_count); - self.rx_buffers.resize_with(self.buffer_count, || None); - self.tx_buffers = Vec::with_capacity(self.buffer_count); - self.tx_buffers.resize_with(self.buffer_count, || None); - } - - unsafe fn setup_virtual_queues(&mut self) { - self.virtual_queues = Some(VirtualQueues { - receive_queue: VirtQueue { - descriptors: vec![VirtqDescriptor::default(); self.queue_size as usize], - available: VirtqAvailable::new(self.queue_size), - used: VirtqUsed::new(self.queue_size), - }, - transmit_queue: VirtQueue { - descriptors: vec![VirtqDescriptor::default(); self.queue_size as usize], - available: VirtqAvailable::new(self.queue_size), - used: VirtqUsed::new(self.queue_size), - }, - }); - } - - /// Receive Queues must be 2*N and Transmit Queues must be 2*N + 1 - /// For example, Receive Queue must be 0 and Transmit Queue must be 1 - fn initialize_virtual_queue(&self, queue_index: u16, virt_queue: &VirtQueue) { - self.mmio.accessor.write_queue_select(queue_index); - - self.mmio - .accessor - .write_queue_desc(virt_queue.descriptors.as_ptr() as u64); - self.mmio.accessor.write_queue_driver( - (virt_queue.available.data.as_ref() as *const VirtqAvailablePacked) as u64, - ); - self.mmio - .accessor - .write_queue_device((virt_queue.used.data.as_ref() as *const VirtqUsedPacked) as u64); - self.mmio.accessor.write_queue_enable(1); - } - - /// Returns a free descriptor chain index - /// For Virtio Net, the VirtioNetworkHeader is placed at i and the Packet Buffer will be placed at i + self.buffer_count - fn get_free_idx(free_buffers: &mut Vec) -> Result { - for i in 0..free_buffers.len() { - if free_buffers[i] { - free_buffers[i] = false; - return Ok(i); - } - } - - return Err(()); - } - - #[inline] - fn get_addr(obj: &T) -> u64 { - (obj as *const T) as u64 - } - - /// If the buffer can't be added, it is returned in the Err() - fn add_rx_buffer( - &mut self, - buffer: RRef, - ) -> Result<(), RRef> { - let rx_q = &mut self.virtual_queues.as_mut().unwrap().receive_queue; - - if let Ok(header_idx) = Self::get_free_idx(&mut self.rx_free_descriptors) { - let buffer_idx = header_idx + self.buffer_count; - let buffer_addr = buffer.as_ptr() as u64; - - // Store it so it isn't dropped - self.rx_buffers[header_idx] = Some(buffer); - - // One descriptor points at the network header, chain this with a descriptor to the buffer - // Header - rx_q.descriptors[header_idx] = VirtqDescriptor { - addr: Self::get_addr(&self.virtio_network_headers[header_idx]), - len: core::mem::size_of::() as u32, // 10 bytes - // 1 is NEXT FLAG - // 2 is WRITABLE FLAG - flags: 1 | 2, - next: buffer_idx as u16, - }; - // Actual Buffer - rx_q.descriptors[buffer_idx] = VirtqDescriptor { - addr: buffer_addr, - len: 1514, - flags: 2, - next: 0, - }; - - // Mark the buffer as usable - *rx_q - .available - .ring(rx_q.available.data.idx % self.queue_size) = header_idx as u16; - rx_q.available.data.idx = rx_q.available.data.idx.wrapping_add(1); // We only added one "chain head" - - unsafe { - self.mmio.queue_notify(0, 0); - } - - return Ok(()); - } else { - return Err(buffer); - } - } - - pub fn add_rx_buffers( - &mut self, - packets: &mut RRefDeque, - collect: &mut RRefDeque, - ) { - if packets.len() == 0 { - return; - } - - while let Some(buffer) = packets.pop_front() { - let res = self.add_rx_buffer(buffer); - - if res.is_err() { - packets.push_back(res.unwrap_err()); - break; - } - } - } - - /// Returns an error if there's no free space in the TX queue, Ok otherwise - fn add_tx_packet( - &mut self, - buffer: RRef, - ) -> Result<(), RRef> { - let tx_q = &mut self.virtual_queues.as_mut().unwrap().transmit_queue; - - if let Ok(header_idx) = Self::get_free_idx(&mut self.tx_free_descriptors) { - let buffer_idx = header_idx + self.buffer_count; - let buffer_addr = buffer.as_ptr() as u64; - - // Store it so it isn't dropped - self.tx_buffers[header_idx] = Some(buffer); - - tx_q.descriptors[header_idx] = VirtqDescriptor { - addr: Self::get_addr(&self.virtio_network_headers[header_idx]), - len: core::mem::size_of::() as u32, // 10 bytes - flags: 1, // 1 is next flag - next: buffer_idx as u16, - }; - tx_q.descriptors[buffer_idx] = VirtqDescriptor { - addr: buffer_addr, - len: 1514, - flags: 0, - next: 0, - }; - - *tx_q - .available - .ring(tx_q.available.data.idx % self.queue_size) = header_idx as u16; - tx_q.available.data.idx = tx_q.available.data.idx.wrapping_add(1); - - unsafe { - self.mmio.queue_notify(1, 1); - } - return Ok(()); - } else { - return Err(buffer); - } - } - - pub fn add_tx_buffers(&mut self, packets: &mut RRefDeque) { - if packets.len() == 0 { - return; - } - - while let Some(packet) = packets.pop_front() { - let res = self.add_tx_packet(packet); - - if res.is_err() { - println!("ERROR: VIRTIO NET: COULD NOT ADD TX PACKET. NO FREE SPACE!"); - packets.push_back(res.unwrap_err()); - break; - } - } - } - - /// Adds new packets to `packets`. Returns the number of received packets - /// Returns the number of new packets found - pub fn get_received_packets( - &mut self, - collect: &mut RRefDeque, - ) -> usize { - /// We have to return the number of packets received - let mut new_packets_count = 0; - let rx_q = &mut self.virtual_queues.as_mut().unwrap().receive_queue; - - while self.rx_last_idx != rx_q.used.data.idx { - let used_element = rx_q.used.ring(self.rx_last_idx % self.queue_size); - let header_descriptor = &rx_q.descriptors[used_element.id as usize]; - let buffer_descriptor = &rx_q.descriptors[header_descriptor.next as usize]; - - if let Some(buffer) = self.rx_buffers[used_element.id as usize].take() { - // Processed packets are "collected" - collect.push_back(buffer); - new_packets_count += 1; - - // Free the descriptor - self.rx_free_descriptors[used_element.id as usize] = true; - } else { - println!("ERROR: VIRTIO NET: RX BUFFER MISSING"); - } - - self.rx_last_idx = self.rx_last_idx.wrapping_add(1); - } - - new_packets_count - } - - /// Returns the number of tx packets that have been sent - pub fn free_processed_tx_packets( - &mut self, - packets: &mut RRefDeque, - ) -> usize { - let mut freed_count = 0; - let tx_q = &mut self.virtual_queues.as_mut().unwrap().transmit_queue; - - while self.tx_last_idx != tx_q.used.data.idx { - let used_element = tx_q.used.ring(self.tx_last_idx % self.queue_size); - let header_descriptor = &tx_q.descriptors[used_element.id as usize]; - let buffer_descriptor = &tx_q.descriptors[header_descriptor.next as usize]; - - if let Some(buffer) = self.tx_buffers[used_element.id as usize].take() { - packets.push_back(buffer); - freed_count += 1; - - // Free the descriptor - self.tx_free_descriptors[used_element.id as usize] = true; - } else { - println!("ERROR: VIRTIO NET: TX BUFFER MISSING"); - } - - self.tx_last_idx = self.tx_last_idx.wrapping_add(1); - } - - freed_count - } -} diff --git a/domains/sys/driver/virtio_net_mmio/Cargo.toml b/domains/sys/driver/virtio_net_mmio/Cargo.toml index 0860b2e5..80d9e08f 100644 --- a/domains/sys/driver/virtio_net_mmio/Cargo.toml +++ b/domains/sys/driver/virtio_net_mmio/Cargo.toml @@ -17,7 +17,7 @@ hashbrown = "0.7.2" redhttpd = { path = "../../../lib/redhttpd" } virtio_device = { path = "../../../../lib/devices/virtio" } -virtio_network_device = { path = "../../../../lib/devices/virtio_net" } +virtio_net_mmio_device = { path = "../../../../lib/devices/virtio_net_mmio" } # Interfaces syscalls = { path = "../../../../lib/core/interfaces/syscalls" } diff --git a/domains/sys/driver/virtio_net_mmio/src/main.rs b/domains/sys/driver/virtio_net_mmio/src/main.rs index b17bf26c..c3460734 100644 --- a/domains/sys/driver/virtio_net_mmio/src/main.rs +++ b/domains/sys/driver/virtio_net_mmio/src/main.rs @@ -6,7 +6,8 @@ const_raw_ptr_to_usize_cast, const_in_array_repeat_expressions, untagged_unions, - maybe_uninit_extra + maybe_uninit_extra, + core_intrinsics )] extern crate alloc; @@ -18,18 +19,19 @@ use alloc::collections::VecDeque; use alloc::sync::Arc; use alloc::vec::Vec; use alloc::{boxed::Box, collections::BTreeMap}; +use core::intrinsics::size_of; +use core::ptr::{read_volatile, write_volatile}; use core::{borrow::BorrowMut, panic::PanicInfo, pin::Pin, usize}; use syscalls::{Heap, Syscall}; use console::{print, println}; use interface::{net::Net, rpc::RpcResult}; -use libsyscalls::syscalls::sys_backtrace; +use libsyscalls::syscalls::{sys_backtrace, sys_yield}; pub use platform::PciBarAddr; use spin::Mutex; pub use interface::error::{ErrorKind, Result}; -use virtio_network_device::pci::PciFactory; -use virtio_network_device::VirtioNetInner; +use virtio_net_mmio_device::VirtioNetInner; use interface::rref::{RRef, RRefDeque}; @@ -37,6 +39,8 @@ use smolnet::{self, SmolPhy}; pub use interface::net::NetworkStats; +const MMIO_CONFIG_ADDRESS: usize = 0x100000; + pub struct VirtioNet(Arc>); impl interface::net::Net for VirtioNet { @@ -124,42 +128,12 @@ pub fn trusted_entry( libsyscalls::syscalls::init(s); interface::rref::init(heap, libsyscalls::syscalls::sys_get_current_domain_id()); - // libbenchnet::run_fwd_udptest_rref(&net, 1514); - - // VIRTIO DEMO LOOP - // Run SmolNet - - // let mut smol = SmolPhy::new(Box::new(net)); - - // use smoltcp::iface::{EthernetInterfaceBuilder, NeighborCache}; - // use smoltcp::socket::SocketSet; - // use smoltcp::time::Instant; - // use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; - - // let neighbor_cache = NeighborCache::new(BTreeMap::new()); - - // let ip_addresses = [IpCidr::new(IpAddress::v4(10, 10, 10, 10), 24)]; - // let mac_address = [0x90, 0xe2, 0xba, 0xb3, 0xb9, 0x10]; - // let mut iface = EthernetInterfaceBuilder::new(smol) - // .ethernet_addr(EthernetAddress::from_bytes(&mac_address)) - // .neighbor_cache(neighbor_cache) - // .ip_addrs(ip_addresses) - // .finalize(); - - // let mut sockets = SocketSet::new(Vec::with_capacity(512)); - - // let mut httpd = redhttpd::Httpd::new(); - - // loop { - // iface.device_mut().do_rx(); - - // let current = libtime::get_ns_time() / 1000000; - // let timestamp = Instant::from_millis(current as i64); + unsafe { + let mut inner = VirtioNetInner::new(MMIO_CONFIG_ADDRESS); + inner.init(); + } - // iface.poll(&mut sockets, timestamp); - // httpd.handle(&mut sockets); - // iface.device_mut().do_tx(); - // } + loop {} Box::new(nullnet::NullNet::new()) } diff --git a/domains/sys/driver/virtio_net_mmio/src/virtio_net.rs b/domains/sys/driver/virtio_net_mmio/src/virtio_net.rs deleted file mode 100644 index ea6b3a84..00000000 --- a/domains/sys/driver/virtio_net_mmio/src/virtio_net.rs +++ /dev/null @@ -1,473 +0,0 @@ -#![no_std] -#![no_main] -#![feature( - box_syntax, - const_fn, - const_raw_ptr_to_usize_cast, - const_in_array_repeat_expressions, - untagged_unions, - maybe_uninit_extra -)] - -extern crate alloc; - -use core::usize; - -use alloc::alloc::{alloc, Layout}; -use alloc::sync::Arc; -use alloc::vec; -use alloc::vec::Vec; -use console::println; -use interface::rref::{RRef, RRefDeque}; -use spin::Mutex; -use virtio_device::defs::{ - VirtQueue, VirtqAvailable, VirtqAvailablePacked, VirtqDescriptor, VirtqUsed, VirtqUsedElement, - VirtqUsedPacked, -}; -use virtio_device::{Mmio, VirtioDeviceStatus}; - -use crate::virtio_device_config_modified; - -#[repr(C, packed)] -pub struct VirtioNetworkDeviceConfig { - mac: [u8; 6], - status: u16, - // Not available without negotiating features VIRTIO_NET_F_MQ and VIRTIO_NET_F_MTU - // max_virtqueue_pairs: u16, - // mtu: u16, -} - -#[derive(Debug, Clone, Copy)] -#[repr(C, packed)] -pub struct VirtioNetworkHeader { - pub flags: u8, - pub gso_type: u8, - pub header_length: u16, - pub gso_size: u16, - pub csum_start: u16, - pub csum_offset: u16, - // pub num_buffers: u16, -} - -struct VirtualQueues { - receive_queue: VirtQueue, - transmit_queue: VirtQueue, -} - -type NetworkPacketBuffer = [u8; 1514]; - -pub struct VirtioNetInner { - mmio: Mmio, - virtual_queues: Option, // None until init() is called - - /// This is the size of the queues used by the device, it is read during init(). - /// It would be less annoying to use if it were usize but it truly is a u16 value. - queue_size: u16, - - /// This tracks the maximum number of buffers or descriptor chains we can simultaneiously have. - /// For the network driver, each network packet requires two descriptors so this will be - /// queue_size / 2. - buffer_count: usize, - - /// Dummy VirtioNetHeaders. - /// The driver doesn't actually use these but they are required by the spec - virtio_network_headers: Vec, - - /// Tracks which descriptors on the queue are free - rx_free_descriptors: Vec, - /// Tracks which descriptors on the queue are free - tx_free_descriptors: Vec, - - /// The last index (of the used ring) that was checked by the driver - rx_last_idx: u16, - /// The last index (of the used ring) that was checked by the driver - tx_last_idx: u16, - - rx_buffers: Vec>>, - tx_buffers: Vec>>, -} - -impl VirtioNetInner { - /// Returns an initialized VirtioNet from a base address. - pub unsafe fn new(mmio_base: usize) -> Self { - Self { - mmio: Mmio::new(mmio_base), - - queue_size: 0, // We will update this (and the vecs) in init() - buffer_count: 0, - - virtual_queues: None, - - virtio_network_headers: vec![], - - rx_free_descriptors: vec![], - tx_free_descriptors: vec![], - - rx_buffers: vec![], - tx_buffers: vec![], - - rx_last_idx: 0, - tx_last_idx: 0, - } - } - - pub fn init(&mut self) { - println!("Initializing Virtio Network Device"); - - // VIRTIO DEVICE INIT - // https://docs.oasis-open.org/virtio/virtio/v1.1/cs01/virtio-v1.1-cs01.html#x1-920001 - // - // Reset the device. - // Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. - // Set the DRIVER status bit: the guest OS knows how to drive the device. - // Read device feature bits, and write the subset of feature bits understood by the OS and driver to the device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration fields to check that it can support the device before accepting it. - // Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. - // Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. - // Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup, reading and possibly writing the device’s virtio configuration space, and population of virtqueues. - // Set the DRIVER_OK status bit. At this point the device is “live”. - - // Reset the device - // Failing to do this DOES cause errors, don't ask how I know *sigh* - self.mmio.accessor.write_device_status(0); - Mmio::memory_fence(); - - // Acknowledge Device - unsafe { - self.mmio - .update_device_status(VirtioDeviceStatus::Acknowledge); - self.mmio.update_device_status(VirtioDeviceStatus::Driver); // But do we really know how to drive the device? - } - - self.negotiate_features(); - - // Tell the Device that feature Negotiation is complete - unsafe { - self.mmio - .update_device_status(VirtioDeviceStatus::FeaturesOk); - } - - // Check that Features OK Bit is still set! - // self.print_device_status(); - if (self.mmio.accessor.read_device_status() & VirtioDeviceStatus::FeaturesOk.value()) == 0 { - panic!("Failed to negotiate Virtio Net features!"); - } - - // Read the queue size - // This value is that largest possible queue size so we will use it to initialize all of our vectors - let queue_size = self.mmio.accessor.read_queue_size(); - if queue_size == 0 { - panic!("ERROR: VIRTIO NET: BAD QUEUE SIZE!"); - } - - self.queue_size = queue_size; - self.buffer_count = (self.queue_size / 2) as usize; // Each buffer requires two descriptors - - unsafe { - self.setup_virtual_queues(); - } - - self.initialize_vectors(); - - // Setup Virtual Queues - self.initialize_virtual_queue(0, &(self.virtual_queues.as_ref().unwrap().receive_queue)); - - // println!("Virtio Net Should Yield here!"); - // self.print_device_config(); - // libsyscalls::syscalls::sys_yield(); - - virtio_device_config_modified(); - - self.initialize_virtual_queue(1, &(self.virtual_queues.as_ref().unwrap().transmit_queue)); - - virtio_device_config_modified(); - - // Tell the Device we're all done, even though we aren't - unsafe { self.mmio.update_device_status(VirtioDeviceStatus::DriverOk) }; - - // self.print_device_status(); - - // self.mmio.accessor.write_queue_select(0); - // self.print_device_config(); - // self.mmio.accessor.write_queue_select(1); - // self.print_device_config(); - - println!("VIRTIO NET READY!"); - } - - /// Negotiates Virtio Driver Features - fn negotiate_features(&mut self) { - let mut driver_features: u32 = 0; - driver_features |= 1 << 5; // Enable Device MAC Address - driver_features |= 1 << 16; // Enable Device Status - - self.mmio.accessor.write_driver_feature(driver_features); // Should be &'d with device_features - } - - pub fn print_device_config(&mut self) { - let mut cfg = unsafe { self.mmio.read_common_config() }; - println!("{:#?}", cfg); - } - - pub fn print_device_status(&mut self) { - let device_status = self.mmio.accessor.read_device_status(); - println!("Device Status Bits: {:b}", device_status); - } - - /// Initializes all the vectors using the set buffer_count - fn initialize_vectors(&mut self) { - self.virtio_network_headers = vec![ - VirtioNetworkHeader { - csum_offset: 0, - csum_start: 0, - flags: 0, - gso_size: 0, - gso_type: 0, - header_length: 0, - }; - self.buffer_count - ]; - - self.rx_free_descriptors = vec![true; self.buffer_count]; - self.tx_free_descriptors = vec![true; self.buffer_count]; - - self.rx_buffers = Vec::with_capacity(self.buffer_count); - self.rx_buffers.resize_with(self.buffer_count, || None); - self.tx_buffers = Vec::with_capacity(self.buffer_count); - self.tx_buffers.resize_with(self.buffer_count, || None); - } - - unsafe fn setup_virtual_queues(&mut self) { - self.virtual_queues = Some(VirtualQueues { - receive_queue: VirtQueue { - descriptors: vec![VirtqDescriptor::default(); self.queue_size as usize], - available: VirtqAvailable::new(self.queue_size), - used: VirtqUsed::new(self.queue_size), - }, - transmit_queue: VirtQueue { - descriptors: vec![VirtqDescriptor::default(); self.queue_size as usize], - available: VirtqAvailable::new(self.queue_size), - used: VirtqUsed::new(self.queue_size), - }, - }); - } - - /// Receive Queues must be 2*N and Transmit Queues must be 2*N + 1 - /// For example, Receive Queue must be 0 and Transmit Queue must be 1 - fn initialize_virtual_queue(&self, queue_index: u16, virt_queue: &VirtQueue) { - self.mmio.accessor.write_queue_select(queue_index); - - self.mmio - .accessor - .write_queue_desc(virt_queue.descriptors.as_ptr() as u64); - self.mmio.accessor.write_queue_driver( - (virt_queue.available.data.as_ref() as *const VirtqAvailablePacked) as u64, - ); - self.mmio - .accessor - .write_queue_device((virt_queue.used.data.as_ref() as *const VirtqUsedPacked) as u64); - self.mmio.accessor.write_queue_enable(1); - } - - /// Returns a free descriptor chain index - /// For Virtio Net, the VirtioNetworkHeader is placed at i and the Packet Buffer will be placed at i + self.buffer_count - fn get_free_idx(free_buffers: &mut Vec) -> Result { - for i in 0..free_buffers.len() { - if free_buffers[i] { - free_buffers[i] = false; - return Ok(i); - } - } - - return Err(()); - } - - #[inline] - fn get_addr(obj: &T) -> u64 { - (obj as *const T) as u64 - } - - /// If the buffer can't be added, it is returned in the Err() - fn add_rx_buffer( - &mut self, - buffer: RRef, - ) -> Result<(), RRef> { - let rx_q = &mut self.virtual_queues.as_mut().unwrap().receive_queue; - - if let Ok(header_idx) = Self::get_free_idx(&mut self.rx_free_descriptors) { - let buffer_idx = header_idx + self.buffer_count; - let buffer_addr = buffer.as_ptr() as u64; - - // Store it so it isn't dropped - self.rx_buffers[header_idx] = Some(buffer); - - // One descriptor points at the network header, chain this with a descriptor to the buffer - // Header - rx_q.descriptors[header_idx] = VirtqDescriptor { - addr: Self::get_addr(&self.virtio_network_headers[header_idx]), - len: core::mem::size_of::() as u32, // 10 bytes - // 1 is NEXT FLAG - // 2 is WRITABLE FLAG - flags: 1 | 2, - next: buffer_idx as u16, - }; - // Actual Buffer - rx_q.descriptors[buffer_idx] = VirtqDescriptor { - addr: buffer_addr, - len: 1514, - flags: 2, - next: 0, - }; - - // Mark the buffer as usable - *rx_q - .available - .ring(rx_q.available.data.idx % self.queue_size) = header_idx as u16; - rx_q.available.data.idx = rx_q.available.data.idx.wrapping_add(1); // We only added one "chain head" - - unsafe { - self.mmio.queue_notify(0, 0); - } - - return Ok(()); - } else { - return Err(buffer); - } - } - - pub fn add_rx_buffers( - &mut self, - packets: &mut RRefDeque, - collect: &mut RRefDeque, - ) { - if packets.len() == 0 { - return; - } - - while let Some(buffer) = packets.pop_front() { - let res = self.add_rx_buffer(buffer); - - if res.is_err() { - packets.push_back(res.unwrap_err()); - break; - } - } - } - - /// Returns an error if there's no free space in the TX queue, Ok otherwise - fn add_tx_packet( - &mut self, - buffer: RRef, - ) -> Result<(), RRef> { - let tx_q = &mut self.virtual_queues.as_mut().unwrap().transmit_queue; - - if let Ok(header_idx) = Self::get_free_idx(&mut self.tx_free_descriptors) { - let buffer_idx = header_idx + self.buffer_count; - let buffer_addr = buffer.as_ptr() as u64; - - // Store it so it isn't dropped - self.tx_buffers[header_idx] = Some(buffer); - - tx_q.descriptors[header_idx] = VirtqDescriptor { - addr: Self::get_addr(&self.virtio_network_headers[header_idx]), - len: core::mem::size_of::() as u32, // 10 bytes - flags: 1, // 1 is next flag - next: buffer_idx as u16, - }; - tx_q.descriptors[buffer_idx] = VirtqDescriptor { - addr: buffer_addr, - len: 1514, - flags: 0, - next: 0, - }; - - *tx_q - .available - .ring(tx_q.available.data.idx % self.queue_size) = header_idx as u16; - tx_q.available.data.idx = tx_q.available.data.idx.wrapping_add(1); - - unsafe { - self.mmio.queue_notify(1, 1); - } - return Ok(()); - } else { - return Err(buffer); - } - } - - pub fn add_tx_buffers(&mut self, packets: &mut RRefDeque) { - if packets.len() == 0 { - return; - } - - while let Some(packet) = packets.pop_front() { - let res = self.add_tx_packet(packet); - - if res.is_err() { - println!("ERROR: VIRTIO NET: COULD NOT ADD TX PACKET. NO FREE SPACE!"); - packets.push_back(res.unwrap_err()); - break; - } - } - } - - /// Adds new packets to `packets`. Returns the number of received packets - /// Returns the number of new packets found - pub fn get_received_packets( - &mut self, - collect: &mut RRefDeque, - ) -> usize { - /// We have to return the number of packets received - let mut new_packets_count = 0; - let rx_q = &mut self.virtual_queues.as_mut().unwrap().receive_queue; - - while self.rx_last_idx != rx_q.used.data.idx { - let used_element = rx_q.used.ring(self.rx_last_idx % self.queue_size); - let header_descriptor = &rx_q.descriptors[used_element.id as usize]; - let buffer_descriptor = &rx_q.descriptors[header_descriptor.next as usize]; - - if let Some(buffer) = self.rx_buffers[used_element.id as usize].take() { - // Processed packets are "collected" - collect.push_back(buffer); - new_packets_count += 1; - - // Free the descriptor - self.rx_free_descriptors[used_element.id as usize] = true; - } else { - println!("ERROR: VIRTIO NET: RX BUFFER MISSING"); - } - - self.rx_last_idx = self.rx_last_idx.wrapping_add(1); - } - - new_packets_count - } - - /// Returns the number of tx packets that have been sent - pub fn free_processed_tx_packets( - &mut self, - packets: &mut RRefDeque, - ) -> usize { - let mut freed_count = 0; - let tx_q = &mut self.virtual_queues.as_mut().unwrap().transmit_queue; - - while self.tx_last_idx != tx_q.used.data.idx { - let used_element = tx_q.used.ring(self.tx_last_idx % self.queue_size); - let header_descriptor = &tx_q.descriptors[used_element.id as usize]; - let buffer_descriptor = &tx_q.descriptors[header_descriptor.next as usize]; - - if let Some(buffer) = self.tx_buffers[used_element.id as usize].take() { - packets.push_back(buffer); - freed_count += 1; - - // Free the descriptor - self.tx_free_descriptors[used_element.id as usize] = true; - } else { - println!("ERROR: VIRTIO NET: TX BUFFER MISSING"); - } - - self.tx_last_idx = self.tx_last_idx.wrapping_add(1); - } - - freed_count - } -} diff --git a/lib/devices/virtio_net_mmio/Cargo.toml b/lib/devices/virtio_net_mmio/Cargo.toml index fe88f116..49622f46 100644 --- a/lib/devices/virtio_net_mmio/Cargo.toml +++ b/lib/devices/virtio_net_mmio/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "virtio_network_device" +name = "virtio_net_mmio_device" version = "0.1.0" authors = ["Redleaf team "] edition = "2018" diff --git a/lib/devices/virtio_net_mmio/src/lib.rs b/lib/devices/virtio_net_mmio/src/lib.rs index d930596b..0a6bcb7c 100644 --- a/lib/devices/virtio_net_mmio/src/lib.rs +++ b/lib/devices/virtio_net_mmio/src/lib.rs @@ -12,15 +12,17 @@ pub mod pci; extern crate alloc; -use core::usize; - use alloc::alloc::{alloc, Layout}; use alloc::sync::Arc; use alloc::vec; use alloc::vec::Vec; use console::println; +use core::mem::size_of; +use core::ptr::{read_volatile, write_volatile}; +use core::usize; use hashbrown::HashMap; use interface::rref::{RRef, RRefDeque}; +use libsyscalls::syscalls::sys_yield; use spin::Mutex; use virtio_device::defs::{ VirtQueue, VirtqAvailable, VirtqAvailablePacked, VirtqDescriptor, VirtqUsed, VirtqUsedElement, @@ -28,6 +30,24 @@ use virtio_device::defs::{ }; use virtio_device::{Mmio, VirtioDeviceStatus}; +const DEVICE_NOTIFY: *mut usize = (0x100000 - size_of::()) as *mut usize; + +fn device_notify() { + unsafe { + let v = read_volatile(DEVICE_NOTIFY); + write_volatile(DEVICE_NOTIFY, v + 1); + + println!("Waiting for device to process notification"); + + // Wait for acknowledgement + while read_volatile(DEVICE_NOTIFY) != 0 { + sys_yield(); + } + } + + println!("Device Processed Notification"); +} + #[repr(C, packed)] pub struct VirtioNetworkDeviceConfig { mac: [u8; 6], @@ -173,12 +193,13 @@ impl VirtioNetInner { // Setup Virtual Queues self.initialize_virtual_queue(0, &(self.virtual_queues.as_ref().unwrap().receive_queue)); - // println!("Virtio Net Should Yield here!"); - // self.print_device_config(); - // libsyscalls::syscalls::sys_yield(); + println!("Should call device_notify"); + device_notify(); self.initialize_virtual_queue(1, &(self.virtual_queues.as_ref().unwrap().transmit_queue)); + device_notify(); + // Tell the Device we're all done, even though we aren't unsafe { self.mmio.update_device_status(VirtioDeviceStatus::DriverOk) }; From b864e7fa54d11ab4ae3311ec8b4efaadec12c5de Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Mon, 30 Aug 2021 12:12:40 -0700 Subject: [PATCH 07/15] Added better notification passing --- domains/Cargo.lock | 2 + domains/sys/driver/virtio_backend/Cargo.toml | 1 + domains/sys/driver/virtio_backend/src/defs.rs | 2 - domains/sys/driver/virtio_backend/src/main.rs | 83 +++++++++---------- lib/devices/virtio_backend/Cargo.toml | 2 - lib/devices/virtio_backend/src/defs.rs | 33 ++++++++ lib/devices/virtio_backend/src/lib.rs | 20 +++++ lib/devices/virtio_net_mmio/Cargo.toml | 2 +- lib/devices/virtio_net_mmio/src/lib.rs | 24 +----- 9 files changed, 101 insertions(+), 68 deletions(-) diff --git a/domains/Cargo.lock b/domains/Cargo.lock index c4b3908c..f4e3c947 100644 --- a/domains/Cargo.lock +++ b/domains/Cargo.lock @@ -1013,6 +1013,7 @@ dependencies = [ "protocol", "spin 0.5.3", "syscalls", + "virtio_backend_trusted", "virtio_device", "virtio_net_mmio", "virtio_net_mmio_device", @@ -1134,6 +1135,7 @@ dependencies = [ "malloc", "pci_driver", "spin 0.5.3", + "virtio_backend_trusted", "virtio_device", "volatile_accessor", ] diff --git a/domains/sys/driver/virtio_backend/Cargo.toml b/domains/sys/driver/virtio_backend/Cargo.toml index db3c2ab3..8a41db0e 100644 --- a/domains/sys/driver/virtio_backend/Cargo.toml +++ b/domains/sys/driver/virtio_backend/Cargo.toml @@ -20,6 +20,7 @@ interface = { path = "../../../../interface/generated" } virtio_net_mmio_device = { path = "../../../../lib/devices/virtio_net_mmio" } virtio_net_mmio = { path = "../virtio_net_mmio" } +virtio_backend_trusted = { path = "../../../../lib/devices/virtio_backend" } virtio_device = { path = "../../../../lib/devices/virtio" } diff --git a/domains/sys/driver/virtio_backend/src/defs.rs b/domains/sys/driver/virtio_backend/src/defs.rs index c4ebbff7..a647f20a 100644 --- a/domains/sys/driver/virtio_backend/src/defs.rs +++ b/domains/sys/driver/virtio_backend/src/defs.rs @@ -1,7 +1,5 @@ use virtio_device::defs::{VirtQueue, VirtqAvailablePacked, VirtqUsedPacked}; -pub const MAX_SUPPORTED_QUEUES: u16 = 3; - #[derive(Debug)] pub struct VirtioBackendQueue { pub queue_index: u16, diff --git a/domains/sys/driver/virtio_backend/src/main.rs b/domains/sys/driver/virtio_backend/src/main.rs index a869731b..85f7d0bb 100644 --- a/domains/sys/driver/virtio_backend/src/main.rs +++ b/domains/sys/driver/virtio_backend/src/main.rs @@ -15,7 +15,7 @@ extern crate malloc; mod defs; -use crate::defs::{VirtioBackendQueue, MAX_SUPPORTED_QUEUES}; +use crate::defs::VirtioBackendQueue; use alloc::{boxed::Box, sync::Arc, vec, vec::Vec}; use console::println; use core::{ @@ -27,56 +27,53 @@ use libsyscalls::syscalls::{sys_backtrace, sys_create_thread, sys_yield}; use libtime::sys_ns_sleep; use spin::{Mutex, MutexGuard, Once}; use syscalls::{Heap, Syscall}; +use virtio_backend_trusted::defs::{DEVICE_NOTIFY, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS}; use virtio_device::VirtioPciCommonConfig; use virtio_net_mmio_device::VirtioNetworkDeviceConfig; -/// Increment this counter whenever you wish to notify the device -const DEVICE_NOTIFY: *mut usize = (0x100000 - size_of::()) as *mut usize; - -const MMIO_ADDRESS: *mut VirtioPciCommonConfig = 0x100000 as *mut VirtioPciCommonConfig; struct VirtioBackendInner { - device_config: VirtioPciCommonConfig, backend_queues: Vec>, } -/// Call this function anytime the frontend modifies device config and backend needs to update -// pub fn virtio_device_config_modified() { -// let mut backend = unsafe { VIRTIO_BACKEND.borrow_mut().lock() }; - -// unsafe { -// // Update the backend's info on the queues -// if backend.device_config.queue_enable == 1 { -// if backend.device_config.queue_select >= MAX_SUPPORTED_QUEUES { -// panic!("Virtio Backend Supports at most {} queues but the device has a queue at index {}", -// MAX_SUPPORTED_QUEUES, -// backend.device_config.queue_select); -// } else { -// // Update the queue information -// let queue = VirtioBackendQueue { -// queue_index: backend.device_config.queue_select, -// queue_enable: true, -// queue_size: backend.device_config.queue_size, -// queue_descriptor: backend.device_config.queue_desc, -// queue_device: backend.device_config.queue_device, -// queue_driver: backend.device_config.queue_driver, - -// device_idx: 0, -// driver_idx: 0, -// }; - -// let index = queue.queue_index; -// backend.backend_queues[index as usize] = Some(queue); -// } -// } - -// println!( -// "virtio_device_config_modified {:#?}", -// &backend.backend_queues -// ); -// } -// } +impl VirtioBackendInner { + /// Call this function anytime the frontend modifies device config and backend needs to update + pub fn update_virtio_device_queue_config(&mut self) { + let device_config = unsafe { read_volatile(MMIO_ADDRESS) }; + + // Update the backend's info on the queues + if device_config.queue_enable == 1 { + if device_config.queue_select >= MAX_SUPPORTED_QUEUES { + panic!("Virtio Backend Supports at most {} queues but the device has a queue at index {}", + MAX_SUPPORTED_QUEUES, + device_config.queue_select); + } + + // Update the queue information + let queue = VirtioBackendQueue { + queue_index: device_config.queue_select, + queue_enable: true, + queue_size: device_config.queue_size, + queue_descriptor: device_config.queue_desc, + queue_device: device_config.queue_device, + queue_driver: device_config.queue_driver, + + device_idx: 0, + driver_idx: 0, + }; + + let index = queue.queue_index; + self.backend_queues[index as usize] = Some(queue); + } + + println!("virtio_device_config_modified {:#?}", &self.backend_queues); + } +} extern "C" fn virtio_backend() { + let mut backend = VirtioBackendInner { + backend_queues: vec![None, None, None], + }; + // Initialize the device config unsafe { write_volatile(DEVICE_NOTIFY, 0); @@ -111,7 +108,7 @@ extern "C" fn virtio_backend() { // println!("DEVICE_NOTIFY: {:#?}", &dn); if dn != 0 { - println!("{:#?}", read_volatile(MMIO_ADDRESS)); + backend.update_virtio_device_queue_config(); write_volatile(DEVICE_NOTIFY, 0); } } diff --git a/lib/devices/virtio_backend/Cargo.toml b/lib/devices/virtio_backend/Cargo.toml index b59463aa..a4028b5d 100644 --- a/lib/devices/virtio_backend/Cargo.toml +++ b/lib/devices/virtio_backend/Cargo.toml @@ -14,8 +14,6 @@ malloc = { path = "../../../lib/core/malloc" } spin = { path = "../../../lib/core/spin-rs" } volatile_accessor = { path = "../../../lib/external/volatile_accessor" } - - virtio_device = { path = "../virtio" } hashbrown = "0.7.2" \ No newline at end of file diff --git a/lib/devices/virtio_backend/src/defs.rs b/lib/devices/virtio_backend/src/defs.rs index a2f95b98..95399f68 100644 --- a/lib/devices/virtio_backend/src/defs.rs +++ b/lib/devices/virtio_backend/src/defs.rs @@ -1,3 +1,36 @@ +use core::mem::size_of; +use virtio_device::VirtioPciCommonConfig; + +pub const MAX_SUPPORTED_QUEUES: u16 = 3; + +pub const MMIO_ADDRESS: *mut VirtioPciCommonConfig = 0x100000 as *mut VirtioPciCommonConfig; +pub const DEVICE_NOTIFY: *mut usize = (0x100000 - size_of::()) as *mut usize; + pub struct VirtioMMIOConfiguration { pub configuration_address: usize, } + +pub enum DeviceNotificationType { + None, + DeviceConfigurationUpdated, + QueueUpdated, +} + +impl DeviceNotificationType { + pub const fn value(&self) -> usize { + match self { + Self::None => 0, + Self::DeviceConfigurationUpdated => 1, + Self::QueueUpdated => 2, + } + } + + pub const fn from_value(value: usize) -> Self { + match value { + 0 => Self::None, + 1 => Self::DeviceConfigurationUpdated, + 2 => Self::QueueUpdated, + _ => Self::None, + } + } +} diff --git a/lib/devices/virtio_backend/src/lib.rs b/lib/devices/virtio_backend/src/lib.rs index 7b5d56ea..678c2076 100644 --- a/lib/devices/virtio_backend/src/lib.rs +++ b/lib/devices/virtio_backend/src/lib.rs @@ -11,3 +11,23 @@ pub mod defs; extern crate alloc; + +use core::ptr::{read_volatile, write_volatile}; + +use defs::{DeviceNotificationType, DEVICE_NOTIFY}; +use libsyscalls::syscalls::sys_yield; + +pub fn device_notify(notification_type: DeviceNotificationType) { + let value = notification_type.value(); + + unsafe { + write_volatile(DEVICE_NOTIFY, value); + + const wait_value: usize = DeviceNotificationType::None.value(); + + // Wait for acknowledgement + while read_volatile(DEVICE_NOTIFY) != wait_value { + sys_yield(); + } + } +} diff --git a/lib/devices/virtio_net_mmio/Cargo.toml b/lib/devices/virtio_net_mmio/Cargo.toml index 49622f46..8d9b6a99 100644 --- a/lib/devices/virtio_net_mmio/Cargo.toml +++ b/lib/devices/virtio_net_mmio/Cargo.toml @@ -17,7 +17,7 @@ volatile_accessor = { path = "../../../lib/external/volatile_accessor" } pci_driver = { path = "../../../lib/core/interfaces/dev/pci/pci_driver" } interface = { path = "../../../interface/generated" } - +virtio_backend_trusted = { path = "../virtio_backend" } virtio_device = { path = "../virtio" } hashbrown = "0.7.2" \ No newline at end of file diff --git a/lib/devices/virtio_net_mmio/src/lib.rs b/lib/devices/virtio_net_mmio/src/lib.rs index 0a6bcb7c..88000c87 100644 --- a/lib/devices/virtio_net_mmio/src/lib.rs +++ b/lib/devices/virtio_net_mmio/src/lib.rs @@ -24,30 +24,14 @@ use hashbrown::HashMap; use interface::rref::{RRef, RRefDeque}; use libsyscalls::syscalls::sys_yield; use spin::Mutex; +use virtio_backend_trusted::defs::DeviceNotificationType; +use virtio_backend_trusted::device_notify; use virtio_device::defs::{ VirtQueue, VirtqAvailable, VirtqAvailablePacked, VirtqDescriptor, VirtqUsed, VirtqUsedElement, VirtqUsedPacked, }; use virtio_device::{Mmio, VirtioDeviceStatus}; -const DEVICE_NOTIFY: *mut usize = (0x100000 - size_of::()) as *mut usize; - -fn device_notify() { - unsafe { - let v = read_volatile(DEVICE_NOTIFY); - write_volatile(DEVICE_NOTIFY, v + 1); - - println!("Waiting for device to process notification"); - - // Wait for acknowledgement - while read_volatile(DEVICE_NOTIFY) != 0 { - sys_yield(); - } - } - - println!("Device Processed Notification"); -} - #[repr(C, packed)] pub struct VirtioNetworkDeviceConfig { mac: [u8; 6], @@ -194,11 +178,11 @@ impl VirtioNetInner { self.initialize_virtual_queue(0, &(self.virtual_queues.as_ref().unwrap().receive_queue)); println!("Should call device_notify"); - device_notify(); + device_notify(DeviceNotificationType::DeviceConfigurationUpdated); self.initialize_virtual_queue(1, &(self.virtual_queues.as_ref().unwrap().transmit_queue)); - device_notify(); + device_notify(DeviceNotificationType::DeviceConfigurationUpdated); // Tell the Device we're all done, even though we aren't unsafe { self.mmio.update_device_status(VirtioDeviceStatus::DriverOk) }; From d5ccd9a36bffc0029c9e5dbff0c46a75debf0bbb Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Fri, 3 Sep 2021 19:55:07 -0700 Subject: [PATCH 08/15] Added ability to read descriptors --- domains/sys/driver/virtio_backend/src/main.rs | 93 ++++++++++++--- .../virtio_backend/src/virtual_queue.rs | 110 ++++++++++++++++++ .../sys/driver/virtio_net_mmio/src/main.rs | 9 +- lib/devices/virtio/src/defs.rs | 14 +++ lib/devices/virtio_net_mmio/src/lib.rs | 8 +- 5 files changed, 212 insertions(+), 22 deletions(-) create mode 100644 domains/sys/driver/virtio_backend/src/virtual_queue.rs diff --git a/domains/sys/driver/virtio_backend/src/main.rs b/domains/sys/driver/virtio_backend/src/main.rs index 85f7d0bb..3cb3d4ac 100644 --- a/domains/sys/driver/virtio_backend/src/main.rs +++ b/domains/sys/driver/virtio_backend/src/main.rs @@ -14,10 +14,11 @@ extern crate alloc; extern crate malloc; mod defs; +mod virtual_queue; use crate::defs::VirtioBackendQueue; use alloc::{boxed::Box, sync::Arc, vec, vec::Vec}; -use console::println; +use console::{print, println}; use core::{ intrinsics::size_of, panic::PanicInfo, @@ -27,17 +28,21 @@ use libsyscalls::syscalls::{sys_backtrace, sys_create_thread, sys_yield}; use libtime::sys_ns_sleep; use spin::{Mutex, MutexGuard, Once}; use syscalls::{Heap, Syscall}; -use virtio_backend_trusted::defs::{DEVICE_NOTIFY, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS}; +use virtio_backend_trusted::defs::{ + DeviceNotificationType, DEVICE_NOTIFY, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, +}; use virtio_device::VirtioPciCommonConfig; use virtio_net_mmio_device::VirtioNetworkDeviceConfig; +use virtual_queue::VirtualQueues; struct VirtioBackendInner { backend_queues: Vec>, + virtual_queues: Vec>, } impl VirtioBackendInner { /// Call this function anytime the frontend modifies device config and backend needs to update - pub fn update_virtio_device_queue_config(&mut self) { + pub fn handle_device_config_update(&mut self) { let device_config = unsafe { read_volatile(MMIO_ADDRESS) }; // Update the backend's info on the queues @@ -61,20 +66,54 @@ impl VirtioBackendInner { driver_idx: 0, }; - let index = queue.queue_index; - self.backend_queues[index as usize] = Some(queue); + let index = queue.queue_index as usize; + self.backend_queues[index] = Some(queue); + self.virtual_queues[index] = Some(VirtualQueues::new( + device_config.queue_desc, + device_config.queue_device, + device_config.queue_driver, + device_config.queue_size, + )) } println!("virtio_device_config_modified {:#?}", &self.backend_queues); } -} -extern "C" fn virtio_backend() { - let mut backend = VirtioBackendInner { - backend_queues: vec![None, None, None], - }; + pub fn handle_queue_notify(&mut self) { + // Since there's currently no way of knowing which queue was updated check them all + for i in 0..self.virtual_queues.len() { + if i % 2 == 0 { + self.process_rx_queue(i); + } + } + } + + pub fn process_rx_queue(&mut self, idx: usize) { + if self.virtual_queues[idx].is_none() { + return; + } + + let queue = self.virtual_queues[idx].as_mut().unwrap(); + + // Check for new requests in available / driver queue + let current_idx = *queue.driver_queue.idx(); + while queue.driver_queue.previous_idx != current_idx { + // Get the index for the descriptor head + let chain_header_idx = &mut queue.descriptor_queue.get_descriptors() + [queue.driver_queue.previous_idx as usize]; + + // Do actual processing here + println!("Chain Descriptor Head: {:#?}", chain_header_idx); + + // Move to the next chain + queue.driver_queue.previous_idx = queue.driver_queue.previous_idx.wrapping_add(1); + } + } + + pub fn process_descriptor(&mut self) {} +} - // Initialize the device config +fn initialize_device_config_space() { unsafe { write_volatile(DEVICE_NOTIFY, 0); @@ -100,22 +139,42 @@ extern "C" fn virtio_backend() { }, ); } +} + +fn process_notifications() -> ! { + let mut backend = VirtioBackendInner { + backend_queues: vec![None, None, None], + virtual_queues: vec![None, None, None], + }; loop { - // println!("Virtio Backend!"); - unsafe { - let dn = read_volatile(DEVICE_NOTIFY); - // println!("DEVICE_NOTIFY: {:#?}", &dn); + let dn = unsafe { read_volatile(DEVICE_NOTIFY) }; - if dn != 0 { - backend.update_virtio_device_queue_config(); + match DeviceNotificationType::from_value(dn) { + DeviceNotificationType::DeviceConfigurationUpdated => { + backend.handle_device_config_update(); + } + DeviceNotificationType::QueueUpdated => { + backend.handle_queue_notify(); + } + DeviceNotificationType::None => {} + } + + if dn != 0 { + unsafe { write_volatile(DEVICE_NOTIFY, 0); } } + sys_yield(); } } +extern "C" fn virtio_backend() { + initialize_device_config_space(); + process_notifications(); +} + #[no_mangle] pub fn trusted_entry(s: Box, heap: Box) { libsyscalls::syscalls::init(s); diff --git a/domains/sys/driver/virtio_backend/src/virtual_queue.rs b/domains/sys/driver/virtio_backend/src/virtual_queue.rs new file mode 100644 index 00000000..fe532bfe --- /dev/null +++ b/domains/sys/driver/virtio_backend/src/virtual_queue.rs @@ -0,0 +1,110 @@ +use core::{mem, ptr::read_volatile}; + +use alloc::{slice, vec::Vec}; +use virtio_device::defs::{ + VirtQueue, VirtqAvailablePacked, VirtqDescriptor, VirtqUsedElement, VirtqUsedPacked, +}; + +pub struct DescriptorQueue { + address: *mut VirtqDescriptor, + queue_size: u16, +} + +impl DescriptorQueue { + pub fn new(address: *mut VirtqDescriptor, queue_size: u16) -> Self { + Self { + address, + queue_size, + } + } + + pub fn get_descriptors(&self) -> &mut [VirtqDescriptor] { + unsafe { slice::from_raw_parts_mut(self.address, self.queue_size as usize) } + } +} + +pub struct DeviceQueue { + address: *mut VirtqUsedPacked, + queue_size: u16, + + pub previous_idx: u16, +} + +impl DeviceQueue { + pub fn new(address: *mut VirtqUsedPacked, queue_size: u16) -> Self { + Self { + address, + queue_size, + + previous_idx: 0, + } + } + + pub fn idx(&mut self) -> &mut u16 { + unsafe { &mut (*self.address).idx } + } + + pub fn ring(&mut self, idx: u16) -> &mut VirtqUsedElement { + assert!(idx < self.queue_size); + + unsafe { (*self.address).ring(idx) } + } +} + +pub struct DriverQueue { + address: *mut VirtqAvailablePacked, + queue_size: u16, + + pub previous_idx: u16, +} + +impl DriverQueue { + pub fn new(address: *mut VirtqAvailablePacked, queue_size: u16) -> Self { + Self { + address, + queue_size, + + previous_idx: 0, + } + } + + pub fn idx(&mut self) -> &u16 { + unsafe { &mut (*self.address).idx } + } + + pub fn ring(&mut self, idx: u16) -> &u16 { + assert!(idx < self.queue_size); + + unsafe { (*self.address).ring(idx) } + } +} + +pub struct VirtualQueues { + pub descriptor_queue: DescriptorQueue, + pub driver_queue: DriverQueue, + pub device_queue: DeviceQueue, +} + +impl VirtualQueues { + pub fn new( + descriptor_queue_address: u64, + device_queue_address: u64, + driver_queue_address: u64, + queue_size: u16, + ) -> Self { + Self { + descriptor_queue: DescriptorQueue::new( + descriptor_queue_address as *mut VirtqDescriptor, + queue_size, + ), + device_queue: DeviceQueue::new( + device_queue_address as *mut VirtqUsedPacked, + queue_size, + ), + driver_queue: DriverQueue::new( + driver_queue_address as *mut VirtqAvailablePacked, + queue_size, + ), + } + } +} diff --git a/domains/sys/driver/virtio_net_mmio/src/main.rs b/domains/sys/driver/virtio_net_mmio/src/main.rs index c3460734..5f3a55d7 100644 --- a/domains/sys/driver/virtio_net_mmio/src/main.rs +++ b/domains/sys/driver/virtio_net_mmio/src/main.rs @@ -128,10 +128,15 @@ pub fn trusted_entry( libsyscalls::syscalls::init(s); interface::rref::init(heap, libsyscalls::syscalls::sys_get_current_domain_id()); - unsafe { + let inner = unsafe { let mut inner = VirtioNetInner::new(MMIO_CONFIG_ADDRESS); inner.init(); - } + inner + }; + + let net = VirtioNet(Arc::new(Mutex::new(inner))); + + libbenchnet::run_fwd_udptest_rref(&net, 1514); loop {} diff --git a/lib/devices/virtio/src/defs.rs b/lib/devices/virtio/src/defs.rs index 058ccbe6..a7d1db30 100644 --- a/lib/devices/virtio/src/defs.rs +++ b/lib/devices/virtio/src/defs.rs @@ -55,6 +55,13 @@ pub struct VirtqUsedPacked { ring: [VirtqUsedElement; 0], // Will have size queue_size } +impl VirtqUsedPacked { + /// The struct does not know its queue size so *YOU* must check that the index is correct! + pub unsafe fn ring(&mut self, idx: u16) -> &mut VirtqUsedElement { + self.ring.get_unchecked_mut(idx as usize) + } +} + #[derive(Debug, Copy, Clone)] #[repr(C, packed(2))] pub struct VirtqAvailablePacked { @@ -67,6 +74,13 @@ pub struct VirtqAvailablePacked { ring: [u16; 0], // Will have size queue_size } +impl VirtqAvailablePacked { + /// The struct does not know its queue size so *YOU* must check that the index is correct! + pub unsafe fn ring(&mut self, idx: u16) -> &mut u16 { + self.ring.get_unchecked_mut(idx as usize) + } +} + pub struct VirtqAvailable { pub data: Box, queue_size: u16, diff --git a/lib/devices/virtio_net_mmio/src/lib.rs b/lib/devices/virtio_net_mmio/src/lib.rs index 88000c87..7d5f75cb 100644 --- a/lib/devices/virtio_net_mmio/src/lib.rs +++ b/lib/devices/virtio_net_mmio/src/lib.rs @@ -327,9 +327,11 @@ impl VirtioNetInner { .ring(rx_q.available.data.idx % self.queue_size) = header_idx as u16; rx_q.available.data.idx = rx_q.available.data.idx.wrapping_add(1); // We only added one "chain head" - unsafe { - self.mmio.queue_notify(0, 0); - } + // unsafe { + // self.mmio.queue_notify(0, 0); + // } + + device_notify(DeviceNotificationType::QueueUpdated); return Ok(()); } else { From 7640dd4d38cc5b319908d05893a5917cc80020af Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Sat, 4 Sep 2021 20:53:09 -0700 Subject: [PATCH 09/15] Working on hooking up network device --- Makefile | 2 +- domains/sys/driver/virtio_backend/src/main.rs | 114 ++++++++++++++++-- .../virtio_backend/src/virtual_queue.rs | 4 + domains/sys/driver/virtio_net/src/main.rs | 2 + domains/sys/init/src/main.rs | 2 +- interface/src/domain_create.rs | 2 +- 6 files changed, 115 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 86a7249a..4908c16d 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ DEBUG ?= false LARGE_MEM ?= true IXGBE ?= true -VIRTIO_NET ?= false +VIRTIO_NET ?= true VIRTIO_BLOCK ?= false ifndef NO_DEFAULT_FLAGS diff --git a/domains/sys/driver/virtio_backend/src/main.rs b/domains/sys/driver/virtio_backend/src/main.rs index 3cb3d4ac..1812ce9c 100644 --- a/domains/sys/driver/virtio_backend/src/main.rs +++ b/domains/sys/driver/virtio_backend/src/main.rs @@ -20,10 +20,15 @@ use crate::defs::VirtioBackendQueue; use alloc::{boxed::Box, sync::Arc, vec, vec::Vec}; use console::{print, println}; use core::{ + borrow::BorrowMut, intrinsics::size_of, panic::PanicInfo, ptr::{read_volatile, write_volatile}, }; +use interface::{ + net::Net, + rref::{RRef, RRefDeque}, +}; use libsyscalls::syscalls::{sys_backtrace, sys_create_thread, sys_yield}; use libtime::sys_ns_sleep; use spin::{Mutex, MutexGuard, Once}; @@ -31,13 +36,23 @@ use syscalls::{Heap, Syscall}; use virtio_backend_trusted::defs::{ DeviceNotificationType, DEVICE_NOTIFY, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, }; -use virtio_device::VirtioPciCommonConfig; +use virtio_device::{defs::VirtQueue, VirtioPciCommonConfig}; use virtio_net_mmio_device::VirtioNetworkDeviceConfig; use virtual_queue::VirtualQueues; +struct VirtioBackendThreadArguments { + net: Box, +} + +static mut THREAD_ARGUMENTS: Option = None; + struct VirtioBackendInner { backend_queues: Vec>, virtual_queues: Vec>, + net: Box, + + receive_queue: Option>, + collect_queue: Option>, } impl VirtioBackendInner { @@ -99,18 +114,85 @@ impl VirtioBackendInner { let current_idx = *queue.driver_queue.idx(); while queue.driver_queue.previous_idx != current_idx { // Get the index for the descriptor head - let chain_header_idx = &mut queue.descriptor_queue.get_descriptors() - [queue.driver_queue.previous_idx as usize]; + let chain_header_idx = + queue.driver_queue.previous_idx % queue.descriptor_queue.queue_size(); // Do actual processing here - println!("Chain Descriptor Head: {:#?}", chain_header_idx); + // Self::print_descriptor_chain(queue, chain_header_idx); + Self::rx_process_descriptor_chain( + queue, + chain_header_idx, + self.receive_queue.as_mut().unwrap(), + ); // Move to the next chain queue.driver_queue.previous_idx = queue.driver_queue.previous_idx.wrapping_add(1); } + + // Give all collected buffers to the device + if let Ok(Ok((_, packets, collect))) = self.net.submit_and_poll_rref( + self.receive_queue.take().unwrap(), + self.collect_queue.take().unwrap(), + false, + 1514, + ) { + self.receive_queue.replace(packets); + self.collect_queue.replace(collect); + } else { + panic!("Communication with backend device failed!"); + } + } + + /// Adds the Virtio RX Descriptor to the actual device's RX Queue + fn rx_process_descriptor_chain( + queue: &VirtualQueues, + chain_header_idx: u16, + device_queue: &mut RRefDeque<[u8; 1514], 32>, + ) { + // Only add the first descriptor of size 1514 in the chain + let mut current_idx: usize = chain_header_idx.into(); + let descriptors = queue.descriptor_queue.get_descriptors(); + + loop { + let descriptor = descriptors[current_idx]; + + if descriptor.len == 1514 { + // Add it to the device and break + let buffer = unsafe { *(descriptor.addr as *mut [u8; 1514]) }; + device_queue.push_back(RRef::new(buffer)); + break; + } else { + // Try the next descriptor + if (descriptor.flags & 0b1) == 0b1 { + current_idx = descriptor.next.into(); + } else { + break; + } + } + } } - pub fn process_descriptor(&mut self) {} + fn print_descriptor_chain(queue: &VirtualQueues, chain_header_idx: u16) { + let mut current_idx: usize = chain_header_idx.into(); + let descriptors = queue.descriptor_queue.get_descriptors(); + + println!("---CHAIN {} START---", chain_header_idx); + + loop { + // Get and print the descriptor + let descriptor = descriptors[current_idx]; + println!("{:#?}", &descriptor); + + if (descriptor.flags & 0b1) == 0b1 { + // Goto Next + current_idx = descriptor.next.into(); + } else { + break; + } + } + + println!("---CHAIN {} END---", chain_header_idx); + } } fn initialize_device_config_space() { @@ -141,10 +223,14 @@ fn initialize_device_config_space() { } } -fn process_notifications() -> ! { +fn process_notifications(net: Box) -> ! { let mut backend = VirtioBackendInner { backend_queues: vec![None, None, None], virtual_queues: vec![None, None, None], + net, + + receive_queue: Some(RRefDeque::new([None; 32])), + collect_queue: Some(RRefDeque::new([None; 32])), }; loop { @@ -171,15 +257,27 @@ fn process_notifications() -> ! { } extern "C" fn virtio_backend() { + // Retrieve Thread Arguments + let args = unsafe { THREAD_ARGUMENTS.take().unwrap() }; + initialize_device_config_space(); - process_notifications(); + process_notifications(args.net); } #[no_mangle] -pub fn trusted_entry(s: Box, heap: Box) { +pub fn trusted_entry( + s: Box, + heap: Box, + net: Box, +) { libsyscalls::syscalls::init(s); interface::rref::init(heap, libsyscalls::syscalls::sys_get_current_domain_id()); + // Prepare thread arguments + unsafe { + THREAD_ARGUMENTS = Some(VirtioBackendThreadArguments { net }); + } + sys_create_thread("virtio_backend", virtio_backend); } diff --git a/domains/sys/driver/virtio_backend/src/virtual_queue.rs b/domains/sys/driver/virtio_backend/src/virtual_queue.rs index fe532bfe..58c2613d 100644 --- a/domains/sys/driver/virtio_backend/src/virtual_queue.rs +++ b/domains/sys/driver/virtio_backend/src/virtual_queue.rs @@ -21,6 +21,10 @@ impl DescriptorQueue { pub fn get_descriptors(&self) -> &mut [VirtqDescriptor] { unsafe { slice::from_raw_parts_mut(self.address, self.queue_size as usize) } } + + pub fn queue_size(&self) -> u16 { + self.queue_size + } } pub struct DeviceQueue { diff --git a/domains/sys/driver/virtio_net/src/main.rs b/domains/sys/driver/virtio_net/src/main.rs index 393909ce..f791fb02 100644 --- a/domains/sys/driver/virtio_net/src/main.rs +++ b/domains/sys/driver/virtio_net/src/main.rs @@ -125,6 +125,8 @@ pub fn trusted_entry( libsyscalls::syscalls::init(s); interface::rref::init(heap, libsyscalls::syscalls::sys_get_current_domain_id()); + println!("virtio_net::trusted_entry()"); + #[cfg(feature = "virtio_net")] let net = { let net = { diff --git a/domains/sys/init/src/main.rs b/domains/sys/init/src/main.rs index 8bcb75d2..003c52a4 100644 --- a/domains/sys/init/src/main.rs +++ b/domains/sys/init/src/main.rs @@ -251,7 +251,7 @@ pub fn trusted_entry( let (_) = proxy .as_domain_create_CreateVirtioBackend() - .create_domain_virtio_backend(); + .create_domain_virtio_backend(net); let (_, net) = proxy .as_domain_create_CreateVirtioNetMMIO() diff --git a/interface/src/domain_create.rs b/interface/src/domain_create.rs index 303f53b3..95d8d3dd 100644 --- a/interface/src/domain_create.rs +++ b/interface/src/domain_create.rs @@ -91,7 +91,7 @@ pub trait CreateVirtioBlock: Send + Sync { #[domain_create(path = "virtio_backend")] pub trait CreateVirtioBackend: Send + Sync { - fn create_domain_virtio_backend(&self) -> (Box, ()); + fn create_domain_virtio_backend(&self, net: Box) -> (Box, ()); } #[domain_create(path = "virtio_net_mmio")] From 59c32bf1f4bfec791398054ad3a4bbc93cde94ed Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Mon, 6 Sep 2021 14:45:49 -0700 Subject: [PATCH 10/15] Refactored a bit --- Makefile | 6 +- .../sys/driver/virtio_backend/src/backend.rs | 202 ++++++++++++++++++ domains/sys/driver/virtio_backend/src/main.rs | 163 +------------- .../virtio_backend/src/virtual_queue.rs | 4 +- lib/devices/virtio_backend/src/defs.rs | 4 + 5 files changed, 215 insertions(+), 164 deletions(-) create mode 100644 domains/sys/driver/virtio_backend/src/backend.rs diff --git a/Makefile b/Makefile index 4908c16d..9c33ccd3 100644 --- a/Makefile +++ b/Makefile @@ -103,8 +103,8 @@ qemu_common += -cpu 'Haswell,pdpe1gb' -machine q35 # qemu_common += -device vfio-pci,romfile=,host=06:00.1 # qemu_common += -vnc 127.0.0.1:0 # qemu_common += -mem-path /dev/hugepages -# qemu_common += --trace virtio_* -# qemu_common += --trace virtqueue_* +qemu_common += --trace virtio_* +qemu_common += --trace virtqueue_* # qemu_common += --trace file_* # qemu_common += --trace vhost_* # qemu_common += --trace vfio_* @@ -206,7 +206,7 @@ idl_generation: tools/redIDL then echo "redIDL not found. Maybe you want to do 'git submodule init && git submodule update' then try again?"; \ exit -1; \ fi - make -C interface + # make -C interface .PHONY: domains domains: idl_generation $(xv6fs_img) memops diff --git a/domains/sys/driver/virtio_backend/src/backend.rs b/domains/sys/driver/virtio_backend/src/backend.rs new file mode 100644 index 00000000..fab6ae13 --- /dev/null +++ b/domains/sys/driver/virtio_backend/src/backend.rs @@ -0,0 +1,202 @@ +use core::ptr::read_volatile; + +use alloc::vec; +use alloc::{boxed::Box, vec::Vec}; +use console::println; +use interface::{ + net::Net, + rref::{RRef, RRefDeque}, +}; +use virtio_backend_trusted::defs::{ + BATCH_SIZE, BUFFER, BUFFER_PTR, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, +}; + +use crate::{defs::VirtioBackendQueue, virtual_queue::VirtualQueues}; + +pub struct VirtioBackendInner { + backend_queues: Vec>, + virtual_queues: Vec>, + net: Box, + + /// Used to hold the buffer pointers internally when moving them from the virtual queues to the device + buffers: [Vec; MAX_SUPPORTED_QUEUES as usize], + + /// Used so that we don't have to create RRefDeques when calling submit_and_poll_rref() + /// 0 is packets and 1 is collect + rref_queues: [Option>; 2], +} + +impl VirtioBackendInner { + pub fn new(net: Box) -> Self { + VirtioBackendInner { + backend_queues: vec![None, None, None], + virtual_queues: vec![None, None, None], + net, + + buffers: [ + Vec::with_capacity(BATCH_SIZE), + Vec::with_capacity(BATCH_SIZE), + Vec::with_capacity(BATCH_SIZE), + ], + + rref_queues: [ + Some(RRefDeque::new([None; 32])), + Some(RRefDeque::new([None; 32])), + ], + } + } + + const fn is_rx_queue(queue_idx: usize) -> bool { + queue_idx % 2 == 0 + } + + /// Call this function anytime the frontend modifies device config and backend needs to update + pub fn handle_device_config_update(&mut self) { + let device_config = unsafe { read_volatile(MMIO_ADDRESS) }; + + // Update the backend's info on the queues + if device_config.queue_enable == 1 { + if device_config.queue_select >= MAX_SUPPORTED_QUEUES { + panic!("Virtio Backend Supports at most {} queues but the device has a queue at index {}", + MAX_SUPPORTED_QUEUES, + device_config.queue_select); + } + + // Update the queue information + let queue = VirtioBackendQueue { + queue_index: device_config.queue_select, + queue_enable: true, + queue_size: device_config.queue_size, + queue_descriptor: device_config.queue_desc, + queue_device: device_config.queue_device, + queue_driver: device_config.queue_driver, + + device_idx: 0, + driver_idx: 0, + }; + + let index = queue.queue_index as usize; + self.backend_queues[index] = Some(queue); + self.virtual_queues[index] = Some(VirtualQueues::new( + device_config.queue_desc, + device_config.queue_device, + device_config.queue_driver, + device_config.queue_size, + )) + } + + println!("virtio_device_config_modified {:#?}", &self.backend_queues); + } + + pub fn handle_queue_notify(&mut self) { + // Since there's currently no way of knowing which queue was updated check them all + for i in 0..2 { + self.process_virtual_queue(i); + } + } + + /// Finds applicable buffers in the queue and moves them to the buffer_vec + fn fetch_buffers_from_queue(queue: &mut VirtualQueues, buffer_vec: &mut Vec) { + // Check for new requests in available / driver queue + let driver_idx = *queue.driver_queue.idx(); + while queue.driver_queue.previous_idx != driver_idx && buffer_vec.len() < BATCH_SIZE { + println!( + "Available Chains: {}", + driver_idx - queue.driver_queue.previous_idx + ); + + let descriptors = queue.descriptor_queue.get_descriptors(); + + // Get the index for the descriptor head + let mut current_idx = + (queue.driver_queue.previous_idx % queue.descriptor_queue.queue_size()) as usize; + + // Do actual processing here + loop { + let descriptor = descriptors[current_idx]; + + if descriptor.len == 1514 { + // Add it to the device and break + buffer_vec.push(descriptor.addr as BUFFER_PTR); + break; + } else { + // Try the next descriptor + if (descriptor.flags & 0b1) == 0b1 { + current_idx = descriptor.next.into(); + } else { + break; + } + } + } + + // Move to the next chain + queue.driver_queue.previous_idx = queue.driver_queue.previous_idx.wrapping_add(1); + } + } + + fn move_buffers_to_rref_deque( + buffer_vec: &mut Vec, + rref_deque: &mut RRefDeque, + ) { + while buffer_vec.len() != 0 && rref_deque.len() < 32 { + let ptr = buffer_vec.remove(0); + let r = RRef::new(unsafe { *ptr }); + rref_deque.push_back(r); + } + } + + fn process_virtual_queue(&mut self, queue_idx: usize) { + Self::fetch_buffers_from_queue( + self.virtual_queues[queue_idx].as_mut().unwrap(), + &mut self.buffers[queue_idx], + ); + + println!( + "Submitting {} buffers to device", + self.buffers[queue_idx].len() + ); + self.submit_to_device(queue_idx); + } + + fn submit_to_device(&mut self, queue_idx: usize) { + Self::move_buffers_to_rref_deque( + &mut self.buffers[queue_idx], + self.rref_queues[queue_idx].as_mut().unwrap(), + ); + + // Give all collected buffers to the device + if let Ok(Ok((_, packets, collect))) = self.net.submit_and_poll_rref( + self.rref_queues[0].take().unwrap(), + self.rref_queues[1].take().unwrap(), + !Self::is_rx_queue(queue_idx), + 1514, + ) { + self.rref_queues[0].replace(packets); + self.rref_queues[1].replace(collect); + } else { + panic!("Communication with backend device failed!"); + } + } + + fn print_descriptor_chain(queue: &VirtualQueues, chain_header_idx: u16) { + let mut current_idx: usize = chain_header_idx.into(); + let descriptors = queue.descriptor_queue.get_descriptors(); + + println!("---CHAIN {} START---", chain_header_idx); + + loop { + // Get and print the descriptor + let descriptor = descriptors[current_idx]; + println!("{:#?}", &descriptor); + + if (descriptor.flags & 0b1) == 0b1 { + // Goto Next + current_idx = descriptor.next.into(); + } else { + break; + } + } + + println!("---CHAIN {} END---", chain_header_idx); + } +} diff --git a/domains/sys/driver/virtio_backend/src/main.rs b/domains/sys/driver/virtio_backend/src/main.rs index 1812ce9c..9c8db188 100644 --- a/domains/sys/driver/virtio_backend/src/main.rs +++ b/domains/sys/driver/virtio_backend/src/main.rs @@ -13,10 +13,11 @@ extern crate alloc; extern crate malloc; +mod backend; mod defs; mod virtual_queue; -use crate::defs::VirtioBackendQueue; +use crate::{backend::VirtioBackendInner, defs::VirtioBackendQueue}; use alloc::{boxed::Box, sync::Arc, vec, vec::Vec}; use console::{print, println}; use core::{ @@ -34,7 +35,7 @@ use libtime::sys_ns_sleep; use spin::{Mutex, MutexGuard, Once}; use syscalls::{Heap, Syscall}; use virtio_backend_trusted::defs::{ - DeviceNotificationType, DEVICE_NOTIFY, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, + DeviceNotificationType, BATCH_SIZE, BUFFER, DEVICE_NOTIFY, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, }; use virtio_device::{defs::VirtQueue, VirtioPciCommonConfig}; use virtio_net_mmio_device::VirtioNetworkDeviceConfig; @@ -46,155 +47,6 @@ struct VirtioBackendThreadArguments { static mut THREAD_ARGUMENTS: Option = None; -struct VirtioBackendInner { - backend_queues: Vec>, - virtual_queues: Vec>, - net: Box, - - receive_queue: Option>, - collect_queue: Option>, -} - -impl VirtioBackendInner { - /// Call this function anytime the frontend modifies device config and backend needs to update - pub fn handle_device_config_update(&mut self) { - let device_config = unsafe { read_volatile(MMIO_ADDRESS) }; - - // Update the backend's info on the queues - if device_config.queue_enable == 1 { - if device_config.queue_select >= MAX_SUPPORTED_QUEUES { - panic!("Virtio Backend Supports at most {} queues but the device has a queue at index {}", - MAX_SUPPORTED_QUEUES, - device_config.queue_select); - } - - // Update the queue information - let queue = VirtioBackendQueue { - queue_index: device_config.queue_select, - queue_enable: true, - queue_size: device_config.queue_size, - queue_descriptor: device_config.queue_desc, - queue_device: device_config.queue_device, - queue_driver: device_config.queue_driver, - - device_idx: 0, - driver_idx: 0, - }; - - let index = queue.queue_index as usize; - self.backend_queues[index] = Some(queue); - self.virtual_queues[index] = Some(VirtualQueues::new( - device_config.queue_desc, - device_config.queue_device, - device_config.queue_driver, - device_config.queue_size, - )) - } - - println!("virtio_device_config_modified {:#?}", &self.backend_queues); - } - - pub fn handle_queue_notify(&mut self) { - // Since there's currently no way of knowing which queue was updated check them all - for i in 0..self.virtual_queues.len() { - if i % 2 == 0 { - self.process_rx_queue(i); - } - } - } - - pub fn process_rx_queue(&mut self, idx: usize) { - if self.virtual_queues[idx].is_none() { - return; - } - - let queue = self.virtual_queues[idx].as_mut().unwrap(); - - // Check for new requests in available / driver queue - let current_idx = *queue.driver_queue.idx(); - while queue.driver_queue.previous_idx != current_idx { - // Get the index for the descriptor head - let chain_header_idx = - queue.driver_queue.previous_idx % queue.descriptor_queue.queue_size(); - - // Do actual processing here - // Self::print_descriptor_chain(queue, chain_header_idx); - Self::rx_process_descriptor_chain( - queue, - chain_header_idx, - self.receive_queue.as_mut().unwrap(), - ); - - // Move to the next chain - queue.driver_queue.previous_idx = queue.driver_queue.previous_idx.wrapping_add(1); - } - - // Give all collected buffers to the device - if let Ok(Ok((_, packets, collect))) = self.net.submit_and_poll_rref( - self.receive_queue.take().unwrap(), - self.collect_queue.take().unwrap(), - false, - 1514, - ) { - self.receive_queue.replace(packets); - self.collect_queue.replace(collect); - } else { - panic!("Communication with backend device failed!"); - } - } - - /// Adds the Virtio RX Descriptor to the actual device's RX Queue - fn rx_process_descriptor_chain( - queue: &VirtualQueues, - chain_header_idx: u16, - device_queue: &mut RRefDeque<[u8; 1514], 32>, - ) { - // Only add the first descriptor of size 1514 in the chain - let mut current_idx: usize = chain_header_idx.into(); - let descriptors = queue.descriptor_queue.get_descriptors(); - - loop { - let descriptor = descriptors[current_idx]; - - if descriptor.len == 1514 { - // Add it to the device and break - let buffer = unsafe { *(descriptor.addr as *mut [u8; 1514]) }; - device_queue.push_back(RRef::new(buffer)); - break; - } else { - // Try the next descriptor - if (descriptor.flags & 0b1) == 0b1 { - current_idx = descriptor.next.into(); - } else { - break; - } - } - } - } - - fn print_descriptor_chain(queue: &VirtualQueues, chain_header_idx: u16) { - let mut current_idx: usize = chain_header_idx.into(); - let descriptors = queue.descriptor_queue.get_descriptors(); - - println!("---CHAIN {} START---", chain_header_idx); - - loop { - // Get and print the descriptor - let descriptor = descriptors[current_idx]; - println!("{:#?}", &descriptor); - - if (descriptor.flags & 0b1) == 0b1 { - // Goto Next - current_idx = descriptor.next.into(); - } else { - break; - } - } - - println!("---CHAIN {} END---", chain_header_idx); - } -} - fn initialize_device_config_space() { unsafe { write_volatile(DEVICE_NOTIFY, 0); @@ -224,14 +76,7 @@ fn initialize_device_config_space() { } fn process_notifications(net: Box) -> ! { - let mut backend = VirtioBackendInner { - backend_queues: vec![None, None, None], - virtual_queues: vec![None, None, None], - net, - - receive_queue: Some(RRefDeque::new([None; 32])), - collect_queue: Some(RRefDeque::new([None; 32])), - }; + let mut backend = VirtioBackendInner::new(net); loop { let dn = unsafe { read_volatile(DEVICE_NOTIFY) }; diff --git a/domains/sys/driver/virtio_backend/src/virtual_queue.rs b/domains/sys/driver/virtio_backend/src/virtual_queue.rs index 58c2613d..9b710209 100644 --- a/domains/sys/driver/virtio_backend/src/virtual_queue.rs +++ b/domains/sys/driver/virtio_backend/src/virtual_queue.rs @@ -72,8 +72,8 @@ impl DriverQueue { } } - pub fn idx(&mut self) -> &u16 { - unsafe { &mut (*self.address).idx } + pub fn idx(&self) -> &u16 { + unsafe { &(*self.address).idx } } pub fn ring(&mut self, idx: u16) -> &u16 { diff --git a/lib/devices/virtio_backend/src/defs.rs b/lib/devices/virtio_backend/src/defs.rs index 95399f68..6ec7ff91 100644 --- a/lib/devices/virtio_backend/src/defs.rs +++ b/lib/devices/virtio_backend/src/defs.rs @@ -2,10 +2,14 @@ use core::mem::size_of; use virtio_device::VirtioPciCommonConfig; pub const MAX_SUPPORTED_QUEUES: u16 = 3; +pub const BATCH_SIZE: usize = 32; pub const MMIO_ADDRESS: *mut VirtioPciCommonConfig = 0x100000 as *mut VirtioPciCommonConfig; pub const DEVICE_NOTIFY: *mut usize = (0x100000 - size_of::()) as *mut usize; +pub type BUFFER = [u8; 1514]; +pub type BUFFER_PTR = *const BUFFER; + pub struct VirtioMMIOConfiguration { pub configuration_address: usize, } From 111591d3699b3c164bb2e419ed80fa850f111c72 Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Thu, 9 Sep 2021 21:19:56 -0700 Subject: [PATCH 11/15] Refactored a bit --- .../sys/driver/virtio_backend/src/backend.rs | 202 ---------------- domains/sys/driver/virtio_backend/src/defs.rs | 4 +- domains/sys/driver/virtio_backend/src/main.rs | 11 +- .../virtio_backend/src/virtio_backend.rs | 224 ++++++++++++++++++ .../virtio_backend/src/virtual_queue.rs | 117 ++++++++- lib/devices/virtio_backend/src/defs.rs | 2 +- lib/devices/virtio_net_mmio/src/lib.rs | 1 + 7 files changed, 342 insertions(+), 219 deletions(-) delete mode 100644 domains/sys/driver/virtio_backend/src/backend.rs create mode 100644 domains/sys/driver/virtio_backend/src/virtio_backend.rs diff --git a/domains/sys/driver/virtio_backend/src/backend.rs b/domains/sys/driver/virtio_backend/src/backend.rs deleted file mode 100644 index fab6ae13..00000000 --- a/domains/sys/driver/virtio_backend/src/backend.rs +++ /dev/null @@ -1,202 +0,0 @@ -use core::ptr::read_volatile; - -use alloc::vec; -use alloc::{boxed::Box, vec::Vec}; -use console::println; -use interface::{ - net::Net, - rref::{RRef, RRefDeque}, -}; -use virtio_backend_trusted::defs::{ - BATCH_SIZE, BUFFER, BUFFER_PTR, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, -}; - -use crate::{defs::VirtioBackendQueue, virtual_queue::VirtualQueues}; - -pub struct VirtioBackendInner { - backend_queues: Vec>, - virtual_queues: Vec>, - net: Box, - - /// Used to hold the buffer pointers internally when moving them from the virtual queues to the device - buffers: [Vec; MAX_SUPPORTED_QUEUES as usize], - - /// Used so that we don't have to create RRefDeques when calling submit_and_poll_rref() - /// 0 is packets and 1 is collect - rref_queues: [Option>; 2], -} - -impl VirtioBackendInner { - pub fn new(net: Box) -> Self { - VirtioBackendInner { - backend_queues: vec![None, None, None], - virtual_queues: vec![None, None, None], - net, - - buffers: [ - Vec::with_capacity(BATCH_SIZE), - Vec::with_capacity(BATCH_SIZE), - Vec::with_capacity(BATCH_SIZE), - ], - - rref_queues: [ - Some(RRefDeque::new([None; 32])), - Some(RRefDeque::new([None; 32])), - ], - } - } - - const fn is_rx_queue(queue_idx: usize) -> bool { - queue_idx % 2 == 0 - } - - /// Call this function anytime the frontend modifies device config and backend needs to update - pub fn handle_device_config_update(&mut self) { - let device_config = unsafe { read_volatile(MMIO_ADDRESS) }; - - // Update the backend's info on the queues - if device_config.queue_enable == 1 { - if device_config.queue_select >= MAX_SUPPORTED_QUEUES { - panic!("Virtio Backend Supports at most {} queues but the device has a queue at index {}", - MAX_SUPPORTED_QUEUES, - device_config.queue_select); - } - - // Update the queue information - let queue = VirtioBackendQueue { - queue_index: device_config.queue_select, - queue_enable: true, - queue_size: device_config.queue_size, - queue_descriptor: device_config.queue_desc, - queue_device: device_config.queue_device, - queue_driver: device_config.queue_driver, - - device_idx: 0, - driver_idx: 0, - }; - - let index = queue.queue_index as usize; - self.backend_queues[index] = Some(queue); - self.virtual_queues[index] = Some(VirtualQueues::new( - device_config.queue_desc, - device_config.queue_device, - device_config.queue_driver, - device_config.queue_size, - )) - } - - println!("virtio_device_config_modified {:#?}", &self.backend_queues); - } - - pub fn handle_queue_notify(&mut self) { - // Since there's currently no way of knowing which queue was updated check them all - for i in 0..2 { - self.process_virtual_queue(i); - } - } - - /// Finds applicable buffers in the queue and moves them to the buffer_vec - fn fetch_buffers_from_queue(queue: &mut VirtualQueues, buffer_vec: &mut Vec) { - // Check for new requests in available / driver queue - let driver_idx = *queue.driver_queue.idx(); - while queue.driver_queue.previous_idx != driver_idx && buffer_vec.len() < BATCH_SIZE { - println!( - "Available Chains: {}", - driver_idx - queue.driver_queue.previous_idx - ); - - let descriptors = queue.descriptor_queue.get_descriptors(); - - // Get the index for the descriptor head - let mut current_idx = - (queue.driver_queue.previous_idx % queue.descriptor_queue.queue_size()) as usize; - - // Do actual processing here - loop { - let descriptor = descriptors[current_idx]; - - if descriptor.len == 1514 { - // Add it to the device and break - buffer_vec.push(descriptor.addr as BUFFER_PTR); - break; - } else { - // Try the next descriptor - if (descriptor.flags & 0b1) == 0b1 { - current_idx = descriptor.next.into(); - } else { - break; - } - } - } - - // Move to the next chain - queue.driver_queue.previous_idx = queue.driver_queue.previous_idx.wrapping_add(1); - } - } - - fn move_buffers_to_rref_deque( - buffer_vec: &mut Vec, - rref_deque: &mut RRefDeque, - ) { - while buffer_vec.len() != 0 && rref_deque.len() < 32 { - let ptr = buffer_vec.remove(0); - let r = RRef::new(unsafe { *ptr }); - rref_deque.push_back(r); - } - } - - fn process_virtual_queue(&mut self, queue_idx: usize) { - Self::fetch_buffers_from_queue( - self.virtual_queues[queue_idx].as_mut().unwrap(), - &mut self.buffers[queue_idx], - ); - - println!( - "Submitting {} buffers to device", - self.buffers[queue_idx].len() - ); - self.submit_to_device(queue_idx); - } - - fn submit_to_device(&mut self, queue_idx: usize) { - Self::move_buffers_to_rref_deque( - &mut self.buffers[queue_idx], - self.rref_queues[queue_idx].as_mut().unwrap(), - ); - - // Give all collected buffers to the device - if let Ok(Ok((_, packets, collect))) = self.net.submit_and_poll_rref( - self.rref_queues[0].take().unwrap(), - self.rref_queues[1].take().unwrap(), - !Self::is_rx_queue(queue_idx), - 1514, - ) { - self.rref_queues[0].replace(packets); - self.rref_queues[1].replace(collect); - } else { - panic!("Communication with backend device failed!"); - } - } - - fn print_descriptor_chain(queue: &VirtualQueues, chain_header_idx: u16) { - let mut current_idx: usize = chain_header_idx.into(); - let descriptors = queue.descriptor_queue.get_descriptors(); - - println!("---CHAIN {} START---", chain_header_idx); - - loop { - // Get and print the descriptor - let descriptor = descriptors[current_idx]; - println!("{:#?}", &descriptor); - - if (descriptor.flags & 0b1) == 0b1 { - // Goto Next - current_idx = descriptor.next.into(); - } else { - break; - } - } - - println!("---CHAIN {} END---", chain_header_idx); - } -} diff --git a/domains/sys/driver/virtio_backend/src/defs.rs b/domains/sys/driver/virtio_backend/src/defs.rs index a647f20a..e9738588 100644 --- a/domains/sys/driver/virtio_backend/src/defs.rs +++ b/domains/sys/driver/virtio_backend/src/defs.rs @@ -1,7 +1,7 @@ use virtio_device::defs::{VirtQueue, VirtqAvailablePacked, VirtqUsedPacked}; #[derive(Debug)] -pub struct VirtioBackendQueue { +pub struct VirtioQueueConfig { pub queue_index: u16, pub queue_size: u16, pub queue_enable: bool, @@ -16,7 +16,7 @@ pub struct VirtioBackendQueue { pub device_idx: u16, } -impl VirtioBackendQueue { +impl VirtioQueueConfig { pub fn get_driver_queue(&mut self) -> &mut VirtqAvailablePacked { unsafe { return &mut *(self.queue_driver as *mut VirtqAvailablePacked); diff --git a/domains/sys/driver/virtio_backend/src/main.rs b/domains/sys/driver/virtio_backend/src/main.rs index 9c8db188..99097f23 100644 --- a/domains/sys/driver/virtio_backend/src/main.rs +++ b/domains/sys/driver/virtio_backend/src/main.rs @@ -13,11 +13,11 @@ extern crate alloc; extern crate malloc; -mod backend; mod defs; +mod virtio_backend; mod virtual_queue; -use crate::{backend::VirtioBackendInner, defs::VirtioBackendQueue}; +use crate::{defs::VirtioQueueConfig, virtio_backend::VirtioBackend}; use alloc::{boxed::Box, sync::Arc, vec, vec::Vec}; use console::{print, println}; use core::{ @@ -39,7 +39,7 @@ use virtio_backend_trusted::defs::{ }; use virtio_device::{defs::VirtQueue, VirtioPciCommonConfig}; use virtio_net_mmio_device::VirtioNetworkDeviceConfig; -use virtual_queue::VirtualQueues; +use virtual_queue::VirtualQueue; struct VirtioBackendThreadArguments { net: Box, @@ -76,9 +76,12 @@ fn initialize_device_config_space() { } fn process_notifications(net: Box) -> ! { - let mut backend = VirtioBackendInner::new(net); + let mut backend = VirtioBackend::new(net); loop { + // Check device for processed buffers and move to queues + backend.update_queues(); + let dn = unsafe { read_volatile(DEVICE_NOTIFY) }; match DeviceNotificationType::from_value(dn) { diff --git a/domains/sys/driver/virtio_backend/src/virtio_backend.rs b/domains/sys/driver/virtio_backend/src/virtio_backend.rs new file mode 100644 index 00000000..c2749adf --- /dev/null +++ b/domains/sys/driver/virtio_backend/src/virtio_backend.rs @@ -0,0 +1,224 @@ +use core::ptr::read_volatile; + +use alloc::collections::{BTreeMap, VecDeque}; +use alloc::vec; +use alloc::{boxed::Box, vec::Vec}; +use console::println; +use interface::{ + net::Net, + rref::{RRef, RRefDeque}, +}; +use virtio_backend_trusted::defs::{ + BATCH_SIZE, BUFFER, BUFFER_PTR, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, +}; +use virtio_device::defs::VirtqUsedElement; + +use crate::{defs::VirtioQueueConfig, virtual_queue::VirtualQueue}; + +/// fb: Indicates that this is used in the frontend to backend path +/// bf: Indicated that this is used in the backend to frontend path + +pub struct VirtioBackend { + /// A copy of the queue_config's device status + device_status: u8, + + queue_information: Vec>, + virtual_queues: Vec>, + net: Box, + + // *** The below variables are used to simplify communicating with RRef Net Interface *** + /// We have to copy the arrays in order to satisfy the interface so this keeps track of which RRef + /// corresponds to which buffer + buffer_rref_map: BTreeMap, + + /// Used so that we don't have to create RRefDeques when calling submit_and_poll_rref() + /// 0 is packets and 1 is collect + rref_queues: (Option>, Option>), +} + +impl VirtioBackend { + pub fn new(net: Box) -> Self { + VirtioBackend { + device_status: 0, + queue_information: vec![None, None], + virtual_queues: vec![None, None], + net, + + rref_queues: ( + Some(RRefDeque::new([None; 32])), + Some(RRefDeque::new([None; 32])), + ), + buffer_rref_map: BTreeMap::new(), + } + } + + /// According to the VirtIO Net Spec, Even Queues are used for RX and Odd Queues are used for TX + const fn is_rx_queue(queue_idx: usize) -> bool { + queue_idx % 2 == 0 + } + + pub fn device_enabled(&self) -> bool { + self.device_status == 15 + } + + /// Call this function anytime the frontend modifies device config and backend needs to update + pub fn handle_device_config_update(&mut self) { + let device_config = unsafe { read_volatile(MMIO_ADDRESS) }; + + self.device_status = device_config.device_status; + + // Update the backend's info on the queues + if device_config.queue_enable == 1 { + if device_config.queue_select >= MAX_SUPPORTED_QUEUES { + panic!("Virtio Backend Supports at most {} queues but the device has a queue at index {}", + MAX_SUPPORTED_QUEUES, + { device_config.queue_select}); + } + + // Update the queue information + let queue = VirtioQueueConfig { + queue_index: device_config.queue_select, + queue_enable: true, + queue_size: device_config.queue_size, + queue_descriptor: device_config.queue_desc, + queue_device: device_config.queue_device, + queue_driver: device_config.queue_driver, + + device_idx: 0, + driver_idx: 0, + }; + + let index = queue.queue_index as usize; + self.queue_information[index] = Some(queue); + self.virtual_queues[index] = Some(VirtualQueue::new( + device_config.queue_desc, + device_config.queue_device, + device_config.queue_driver, + device_config.queue_size, + Self::is_rx_queue(index), + )) + } + + println!( + "virtio_device_config_modified {:#?}", + &self.queue_information + ); + } + + /// Handles Queue Notifications submitted by the frontend + pub fn handle_queue_notify(&mut self) { + if !self.device_enabled() { + return; + } + + // Since there's currently no way of knowing which queue was updated check them all + for i in 0..self.virtual_queues.len() { + self.notify_virtual_queue(i); + } + } + + fn notify_virtual_queue(&mut self, queue_idx: usize) { + self.move_buffers_from_frontend_to_rref_deque(queue_idx); + + self.call_submit_and_poll_rref(!Self::is_rx_queue(queue_idx)); + + self.move_buffers_from_rref_deque_to_frontend(queue_idx); + } + + fn move_buffers_from_frontend_to_rref_deque(&mut self, queue_idx: usize) { + // Create new RRefs and add them to the queue + let queue = self.virtual_queues[queue_idx].as_mut().unwrap(); + let buffers = queue.fetch_new_buffers(); + let packets = self.rref_queues.0.as_mut().unwrap(); + + let rx = Self::is_rx_queue(queue_idx); + + while buffers.len() > 0 && packets.len() < BATCH_SIZE { + let buffer = buffers.pop_front().unwrap(); + + let rref = RRef::new([0; 1514]); + + if !rx { + // If it's tx we need to copy the buffer's contents into the RRef + unsafe { + core::ptr::copy(buffer, rref.as_ptr() as *mut BUFFER, 1); + } + } + + self.buffer_rref_map + .insert(rref.as_ptr() as u64, buffer as u64); + packets.push_back(rref); + } + } + + fn move_buffers_from_rref_deque_to_frontend(&mut self, queue_idx: usize) { + let rx = Self::is_rx_queue(queue_idx); + self.call_submit_and_poll_rref(!rx); + + let queue = self.virtual_queues[queue_idx].as_mut().unwrap(); + let collect = self.rref_queues.1.as_mut().unwrap(); + + // Move buffers from collect queue + while let Some(rref) = collect.pop_front() { + if let Some(buffer) = self.buffer_rref_map.remove(&(rref.as_ptr() as u64)) { + if rx { + unsafe { + core::ptr::copy(rref.as_ptr() as *mut BUFFER, buffer as *mut BUFFER, 1); + } + } + + queue.mark_buffers_as_complete(&[buffer as BUFFER_PTR]); + } else { + panic!("RRef address must have changed!"); + } + } + } + + pub fn update_queues(&mut self) { + if !self.device_enabled() { + return; + } + + for queue_idx in 0..self.virtual_queues.len() { + self.move_buffers_from_rref_deque_to_frontend(queue_idx); + } + } + + /// Returns the number of packets added to the collect queue by the device + fn call_submit_and_poll_rref(&mut self, tx: bool) -> usize { + if let Ok(Ok((pkt_count, packets, collect))) = self.net.submit_and_poll_rref( + self.rref_queues.0.take().unwrap(), + self.rref_queues.1.take().unwrap(), + tx, + 1514, + ) { + self.rref_queues.0.replace(packets); + self.rref_queues.1.replace(collect); + return pkt_count; + } else { + panic!("Communication with backend device failed!"); + } + } + + fn print_descriptor_chain(queue: &VirtualQueue, chain_header_idx: u16) { + let mut current_idx: usize = chain_header_idx.into(); + let descriptors = queue.descriptor_queue.get_descriptors(); + + println!("---CHAIN {} START---", chain_header_idx); + + loop { + // Get and print the descriptor + let descriptor = descriptors[current_idx]; + println!("{:#?}", &descriptor); + + if (descriptor.flags & 0b1) == 0b1 { + // Goto Next + current_idx = descriptor.next.into(); + } else { + break; + } + } + + println!("---CHAIN {} END---", chain_header_idx); + } +} diff --git a/domains/sys/driver/virtio_backend/src/virtual_queue.rs b/domains/sys/driver/virtio_backend/src/virtual_queue.rs index 9b710209..435e0583 100644 --- a/domains/sys/driver/virtio_backend/src/virtual_queue.rs +++ b/domains/sys/driver/virtio_backend/src/virtual_queue.rs @@ -1,10 +1,16 @@ use core::{mem, ptr::read_volatile}; -use alloc::{slice, vec::Vec}; +use alloc::{ + collections::{BTreeMap, VecDeque}, + slice, + vec::Vec, +}; +use virtio_backend_trusted::defs::{BATCH_SIZE, BUFFER_PTR}; use virtio_device::defs::{ VirtQueue, VirtqAvailablePacked, VirtqDescriptor, VirtqUsedElement, VirtqUsedPacked, }; +#[derive(Debug)] pub struct DescriptorQueue { address: *mut VirtqDescriptor, queue_size: u16, @@ -26,12 +32,10 @@ impl DescriptorQueue { self.queue_size } } - +#[derive(Debug)] pub struct DeviceQueue { address: *mut VirtqUsedPacked, queue_size: u16, - - pub previous_idx: u16, } impl DeviceQueue { @@ -39,8 +43,6 @@ impl DeviceQueue { Self { address, queue_size, - - previous_idx: 0, } } @@ -54,7 +56,7 @@ impl DeviceQueue { unsafe { (*self.address).ring(idx) } } } - +#[derive(Debug)] pub struct DriverQueue { address: *mut VirtqAvailablePacked, queue_size: u16, @@ -82,19 +84,31 @@ impl DriverQueue { unsafe { (*self.address).ring(idx) } } } - -pub struct VirtualQueues { +#[derive(Debug)] +pub struct VirtualQueue { pub descriptor_queue: DescriptorQueue, pub driver_queue: DriverQueue, pub device_queue: DeviceQueue, + + queue_size: u16, + rx_queue: bool, + + // Variables used for efficiency + /// Holds the pointers to buffers that either need to be given to the device (rx queue) or given to the frontend (tx queue) + buffer_deque: VecDeque, + + /// Maps the buffer's ptr to the chain_header_idx + buffer_map: BTreeMap, } -impl VirtualQueues { +impl VirtualQueue { + /// rx_queue should be true if the queue has an even index, false otherwise pub fn new( descriptor_queue_address: u64, device_queue_address: u64, driver_queue_address: u64, queue_size: u16, + rx_queue: bool, ) -> Self { Self { descriptor_queue: DescriptorQueue::new( @@ -109,6 +123,89 @@ impl VirtualQueues { driver_queue_address as *mut VirtqAvailablePacked, queue_size, ), + + queue_size, + rx_queue, + + buffer_deque: VecDeque::with_capacity(BATCH_SIZE), + buffer_map: BTreeMap::new(), + } + } + + pub fn is_rx_queue(&self) -> bool { + self.rx_queue + } + + fn assert_is_rx(&self) { + assert!( + self.rx_queue, + "This function should only be called if the queue is an rx_queue (even index)!" + ); + } + + fn assert_is_tx(&self) { + assert!( + !self.rx_queue, + "This function should only be called if the queue is an tx_queue (odd index)!" + ); + } + + pub fn fetch_new_buffers(&mut self) -> &mut VecDeque { + while self.driver_queue.previous_idx != *self.driver_queue.idx() + && self.buffer_deque.len() < BATCH_SIZE + { + let idx = (self.driver_queue.previous_idx % self.queue_size); + let chain_header_idx = *self.driver_queue.ring(idx); + + let descriptors = self.descriptor_queue.get_descriptors(); + let mut current_idx: usize = chain_header_idx.into(); + + // Find the descriptor with the correct length + loop { + let descriptor = descriptors[current_idx]; + + if descriptor.len == 1514 { + // Add it to the device and break + self.buffer_deque.push_back(descriptor.addr as BUFFER_PTR); + self.buffer_map.insert(descriptor.addr, chain_header_idx); + break; + } else { + // Try the next descriptor + if (descriptor.flags & 0b1) == 0b1 { + current_idx = descriptor.next.into(); + } else { + break; + } + } + } + + // Move to the next chain + self.driver_queue.previous_idx = self.driver_queue.previous_idx.wrapping_add(1); + } + + return &mut self.buffer_deque; + } + + pub fn mark_buffers_as_complete(&mut self, buffers: &[BUFFER_PTR]) { + for buffer in buffers { + // Look up the chain header idx + let buffer_key = (*buffer) as u64; + if let Some(chain_header_idx) = self.buffer_map.remove(&buffer_key) { + // Mark that chain as complete + let idx = *self.device_queue.idx(); + *self.device_queue.ring(idx % self.queue_size) = VirtqUsedElement { + id: chain_header_idx.into(), + len: 1514, + }; + + // Update the idx + *self.device_queue.idx() = idx.wrapping_add(1); + } else { + panic!( + "Buffer Address Changed during processing! FAILED ADDR: {:#?}, MAP: {:#?}", + buffer, self.buffer_map + ); + } } } } diff --git a/lib/devices/virtio_backend/src/defs.rs b/lib/devices/virtio_backend/src/defs.rs index 6ec7ff91..308d929d 100644 --- a/lib/devices/virtio_backend/src/defs.rs +++ b/lib/devices/virtio_backend/src/defs.rs @@ -1,7 +1,7 @@ use core::mem::size_of; use virtio_device::VirtioPciCommonConfig; -pub const MAX_SUPPORTED_QUEUES: u16 = 3; +pub const MAX_SUPPORTED_QUEUES: u16 = 2; pub const BATCH_SIZE: usize = 32; pub const MMIO_ADDRESS: *mut VirtioPciCommonConfig = 0x100000 as *mut VirtioPciCommonConfig; diff --git a/lib/devices/virtio_net_mmio/src/lib.rs b/lib/devices/virtio_net_mmio/src/lib.rs index 7d5f75cb..d896bfcb 100644 --- a/lib/devices/virtio_net_mmio/src/lib.rs +++ b/lib/devices/virtio_net_mmio/src/lib.rs @@ -186,6 +186,7 @@ impl VirtioNetInner { // Tell the Device we're all done, even though we aren't unsafe { self.mmio.update_device_status(VirtioDeviceStatus::DriverOk) }; + device_notify(DeviceNotificationType::DeviceConfigurationUpdated); // self.print_device_status(); From 669af4ca2fa49a6416cbcd4af9c1c65162e3a591 Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Sat, 11 Sep 2021 16:43:32 -0700 Subject: [PATCH 12/15] Silly BTreeMap corruption --- domains/Cargo.lock | 1 + domains/sys/driver/virtio_backend/Cargo.toml | 2 ++ .../driver/virtio_backend/src/virtio_backend.rs | 17 +++++++++++++---- .../driver/virtio_backend/src/virtual_queue.rs | 11 ++++------- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/domains/Cargo.lock b/domains/Cargo.lock index f4e3c947..1f05c64c 100644 --- a/domains/Cargo.lock +++ b/domains/Cargo.lock @@ -1004,6 +1004,7 @@ name = "virtio_backend" version = "0.1.0" dependencies = [ "console", + "hashbrown 0.7.2", "interface", "libsyscalls", "libtime", diff --git a/domains/sys/driver/virtio_backend/Cargo.toml b/domains/sys/driver/virtio_backend/Cargo.toml index 8a41db0e..57d476e9 100644 --- a/domains/sys/driver/virtio_backend/Cargo.toml +++ b/domains/sys/driver/virtio_backend/Cargo.toml @@ -24,5 +24,7 @@ virtio_backend_trusted = { path = "../../../../lib/devices/virtio_backend" } virtio_device = { path = "../../../../lib/devices/virtio" } +hashbrown = "0.7.2" + [features] default = [] \ No newline at end of file diff --git a/domains/sys/driver/virtio_backend/src/virtio_backend.rs b/domains/sys/driver/virtio_backend/src/virtio_backend.rs index c2749adf..6c4f35d6 100644 --- a/domains/sys/driver/virtio_backend/src/virtio_backend.rs +++ b/domains/sys/driver/virtio_backend/src/virtio_backend.rs @@ -1,9 +1,10 @@ use core::ptr::read_volatile; -use alloc::collections::{BTreeMap, VecDeque}; +use alloc::collections::VecDeque; use alloc::vec; use alloc::{boxed::Box, vec::Vec}; use console::println; +use hashbrown::HashMap; use interface::{ net::Net, rref::{RRef, RRefDeque}, @@ -29,7 +30,7 @@ pub struct VirtioBackend { // *** The below variables are used to simplify communicating with RRef Net Interface *** /// We have to copy the arrays in order to satisfy the interface so this keeps track of which RRef /// corresponds to which buffer - buffer_rref_map: BTreeMap, + buffer_rref_map: HashMap, /// Used so that we don't have to create RRefDeques when calling submit_and_poll_rref() /// 0 is packets and 1 is collect @@ -48,7 +49,7 @@ impl VirtioBackend { Some(RRefDeque::new([None; 32])), Some(RRefDeque::new([None; 32])), ), - buffer_rref_map: BTreeMap::new(), + buffer_rref_map: HashMap::new(), } } @@ -157,6 +158,10 @@ impl VirtioBackend { let queue = self.virtual_queues[queue_idx].as_mut().unwrap(); let collect = self.rref_queues.1.as_mut().unwrap(); + assert!( + self.rref_queues.0.as_ref().unwrap().len() == 0, + "Packets queue should be flushed completely!" + ); // Move buffers from collect queue while let Some(rref) = collect.pop_front() { @@ -169,7 +174,11 @@ impl VirtioBackend { queue.mark_buffers_as_complete(&[buffer as BUFFER_PTR]); } else { - panic!("RRef address must have changed!"); + panic!( + "RRef address must have changed! FAILED RREF ADDR: {:#?}, EXPECTED: {:#?}", + rref.as_ptr() as u64, + self.buffer_rref_map + ); } } } diff --git a/domains/sys/driver/virtio_backend/src/virtual_queue.rs b/domains/sys/driver/virtio_backend/src/virtual_queue.rs index 435e0583..152df7ea 100644 --- a/domains/sys/driver/virtio_backend/src/virtual_queue.rs +++ b/domains/sys/driver/virtio_backend/src/virtual_queue.rs @@ -1,10 +1,7 @@ use core::{mem, ptr::read_volatile}; -use alloc::{ - collections::{BTreeMap, VecDeque}, - slice, - vec::Vec, -}; +use alloc::{collections::VecDeque, slice, vec::Vec}; +use hashbrown::HashMap; use virtio_backend_trusted::defs::{BATCH_SIZE, BUFFER_PTR}; use virtio_device::defs::{ VirtQueue, VirtqAvailablePacked, VirtqDescriptor, VirtqUsedElement, VirtqUsedPacked, @@ -98,7 +95,7 @@ pub struct VirtualQueue { buffer_deque: VecDeque, /// Maps the buffer's ptr to the chain_header_idx - buffer_map: BTreeMap, + buffer_map: HashMap, } impl VirtualQueue { @@ -128,7 +125,7 @@ impl VirtualQueue { rx_queue, buffer_deque: VecDeque::with_capacity(BATCH_SIZE), - buffer_map: BTreeMap::new(), + buffer_map: HashMap::new(), } } From d8337c689d96b4db4157e66058e3b2dbaa0b2ca4 Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Sat, 25 Sep 2021 13:35:26 -0700 Subject: [PATCH 13/15] Made virtio_net_mmio use shared memory region for buffers --- Makefile | 4 +-- domains/sys/driver/virtio_backend/src/main.rs | 2 +- .../virtio_backend/src/virtio_backend.rs | 10 +++---- .../virtio_backend/src/virtual_queue.rs | 10 +++---- lib/devices/virtio_backend/src/defs.rs | 6 ++-- lib/devices/virtio_backend/src/lib.rs | 5 ++-- lib/devices/virtio_net_mmio/src/lib.rs | 30 ++++++++++++++++--- 7 files changed, 45 insertions(+), 22 deletions(-) diff --git a/Makefile b/Makefile index 9c33ccd3..dc6b3f1b 100644 --- a/Makefile +++ b/Makefile @@ -103,8 +103,8 @@ qemu_common += -cpu 'Haswell,pdpe1gb' -machine q35 # qemu_common += -device vfio-pci,romfile=,host=06:00.1 # qemu_common += -vnc 127.0.0.1:0 # qemu_common += -mem-path /dev/hugepages -qemu_common += --trace virtio_* -qemu_common += --trace virtqueue_* +# qemu_common += --trace virtio_* +# qemu_common += --trace virtqueue_* # qemu_common += --trace file_* # qemu_common += --trace vhost_* # qemu_common += --trace vfio_* diff --git a/domains/sys/driver/virtio_backend/src/main.rs b/domains/sys/driver/virtio_backend/src/main.rs index 99097f23..e213a001 100644 --- a/domains/sys/driver/virtio_backend/src/main.rs +++ b/domains/sys/driver/virtio_backend/src/main.rs @@ -35,7 +35,7 @@ use libtime::sys_ns_sleep; use spin::{Mutex, MutexGuard, Once}; use syscalls::{Heap, Syscall}; use virtio_backend_trusted::defs::{ - DeviceNotificationType, BATCH_SIZE, BUFFER, DEVICE_NOTIFY, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, + Buffer, DeviceNotificationType, BATCH_SIZE, DEVICE_NOTIFY, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, }; use virtio_device::{defs::VirtQueue, VirtioPciCommonConfig}; use virtio_net_mmio_device::VirtioNetworkDeviceConfig; diff --git a/domains/sys/driver/virtio_backend/src/virtio_backend.rs b/domains/sys/driver/virtio_backend/src/virtio_backend.rs index 6c4f35d6..3c2f59dd 100644 --- a/domains/sys/driver/virtio_backend/src/virtio_backend.rs +++ b/domains/sys/driver/virtio_backend/src/virtio_backend.rs @@ -10,7 +10,7 @@ use interface::{ rref::{RRef, RRefDeque}, }; use virtio_backend_trusted::defs::{ - BATCH_SIZE, BUFFER, BUFFER_PTR, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, + Buffer, BufferPtr, BATCH_SIZE, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, }; use virtio_device::defs::VirtqUsedElement; @@ -34,7 +34,7 @@ pub struct VirtioBackend { /// Used so that we don't have to create RRefDeques when calling submit_and_poll_rref() /// 0 is packets and 1 is collect - rref_queues: (Option>, Option>), + rref_queues: (Option>, Option>), } impl VirtioBackend { @@ -142,7 +142,7 @@ impl VirtioBackend { if !rx { // If it's tx we need to copy the buffer's contents into the RRef unsafe { - core::ptr::copy(buffer, rref.as_ptr() as *mut BUFFER, 1); + core::ptr::copy(buffer, rref.as_ptr() as *mut Buffer, 1); } } @@ -168,11 +168,11 @@ impl VirtioBackend { if let Some(buffer) = self.buffer_rref_map.remove(&(rref.as_ptr() as u64)) { if rx { unsafe { - core::ptr::copy(rref.as_ptr() as *mut BUFFER, buffer as *mut BUFFER, 1); + core::ptr::copy(rref.as_ptr() as *mut Buffer, buffer as *mut Buffer, 1); } } - queue.mark_buffers_as_complete(&[buffer as BUFFER_PTR]); + queue.mark_buffers_as_complete(&[buffer as BufferPtr]); } else { panic!( "RRef address must have changed! FAILED RREF ADDR: {:#?}, EXPECTED: {:#?}", diff --git a/domains/sys/driver/virtio_backend/src/virtual_queue.rs b/domains/sys/driver/virtio_backend/src/virtual_queue.rs index 152df7ea..692993d2 100644 --- a/domains/sys/driver/virtio_backend/src/virtual_queue.rs +++ b/domains/sys/driver/virtio_backend/src/virtual_queue.rs @@ -2,7 +2,7 @@ use core::{mem, ptr::read_volatile}; use alloc::{collections::VecDeque, slice, vec::Vec}; use hashbrown::HashMap; -use virtio_backend_trusted::defs::{BATCH_SIZE, BUFFER_PTR}; +use virtio_backend_trusted::defs::{BufferPtr, BATCH_SIZE}; use virtio_device::defs::{ VirtQueue, VirtqAvailablePacked, VirtqDescriptor, VirtqUsedElement, VirtqUsedPacked, }; @@ -92,7 +92,7 @@ pub struct VirtualQueue { // Variables used for efficiency /// Holds the pointers to buffers that either need to be given to the device (rx queue) or given to the frontend (tx queue) - buffer_deque: VecDeque, + buffer_deque: VecDeque, /// Maps the buffer's ptr to the chain_header_idx buffer_map: HashMap, @@ -147,7 +147,7 @@ impl VirtualQueue { ); } - pub fn fetch_new_buffers(&mut self) -> &mut VecDeque { + pub fn fetch_new_buffers(&mut self) -> &mut VecDeque { while self.driver_queue.previous_idx != *self.driver_queue.idx() && self.buffer_deque.len() < BATCH_SIZE { @@ -163,7 +163,7 @@ impl VirtualQueue { if descriptor.len == 1514 { // Add it to the device and break - self.buffer_deque.push_back(descriptor.addr as BUFFER_PTR); + self.buffer_deque.push_back(descriptor.addr as BufferPtr); self.buffer_map.insert(descriptor.addr, chain_header_idx); break; } else { @@ -183,7 +183,7 @@ impl VirtualQueue { return &mut self.buffer_deque; } - pub fn mark_buffers_as_complete(&mut self, buffers: &[BUFFER_PTR]) { + pub fn mark_buffers_as_complete(&mut self, buffers: &[BufferPtr]) { for buffer in buffers { // Look up the chain header idx let buffer_key = (*buffer) as u64; diff --git a/lib/devices/virtio_backend/src/defs.rs b/lib/devices/virtio_backend/src/defs.rs index 308d929d..9b3d549a 100644 --- a/lib/devices/virtio_backend/src/defs.rs +++ b/lib/devices/virtio_backend/src/defs.rs @@ -6,9 +6,11 @@ pub const BATCH_SIZE: usize = 32; pub const MMIO_ADDRESS: *mut VirtioPciCommonConfig = 0x100000 as *mut VirtioPciCommonConfig; pub const DEVICE_NOTIFY: *mut usize = (0x100000 - size_of::()) as *mut usize; +pub const SHARED_MEMORY_REGION_PTR: *mut usize = + (0x100000 + size_of::() + 0x1000) as *mut usize; -pub type BUFFER = [u8; 1514]; -pub type BUFFER_PTR = *const BUFFER; +pub type Buffer = [u8; 1514]; +pub type BufferPtr = *const Buffer; pub struct VirtioMMIOConfiguration { pub configuration_address: usize, diff --git a/lib/devices/virtio_backend/src/lib.rs b/lib/devices/virtio_backend/src/lib.rs index 678c2076..046ee0ba 100644 --- a/lib/devices/virtio_backend/src/lib.rs +++ b/lib/devices/virtio_backend/src/lib.rs @@ -1,5 +1,4 @@ #![no_std] -#![no_main] #![feature( box_syntax, const_fn, @@ -23,10 +22,10 @@ pub fn device_notify(notification_type: DeviceNotificationType) { unsafe { write_volatile(DEVICE_NOTIFY, value); - const wait_value: usize = DeviceNotificationType::None.value(); + const WAIT_VALUE: usize = DeviceNotificationType::None.value(); // Wait for acknowledgement - while read_volatile(DEVICE_NOTIFY) != wait_value { + while read_volatile(DEVICE_NOTIFY) != WAIT_VALUE { sys_yield(); } } diff --git a/lib/devices/virtio_net_mmio/src/lib.rs b/lib/devices/virtio_net_mmio/src/lib.rs index d896bfcb..78b38489 100644 --- a/lib/devices/virtio_net_mmio/src/lib.rs +++ b/lib/devices/virtio_net_mmio/src/lib.rs @@ -6,7 +6,8 @@ const_raw_ptr_to_usize_cast, const_in_array_repeat_expressions, untagged_unions, - maybe_uninit_extra + maybe_uninit_extra, + array_methods )] pub mod pci; @@ -19,6 +20,7 @@ use alloc::vec::Vec; use console::println; use core::mem::size_of; use core::ptr::{read_volatile, write_volatile}; +use core::slice::{self}; use core::usize; use hashbrown::HashMap; use interface::rref::{RRef, RRefDeque}; @@ -77,6 +79,10 @@ pub struct VirtioNetInner { /// The driver doesn't actually use these but they are required by the spec virtio_network_headers: Vec, + /// The shared memory region for buffers + /// Place tx at header_idx and rx at buffer_idx + virtio_network_buffers: Vec, + /// Tracks which descriptors on the queue are free rx_free_descriptors: Vec, /// Tracks which descriptors on the queue are free @@ -103,6 +109,7 @@ impl VirtioNetInner { virtual_queues: None, virtio_network_headers: vec![], + virtio_network_buffers: vec![], rx_free_descriptors: vec![], tx_free_descriptors: vec![], @@ -231,6 +238,8 @@ impl VirtioNetInner { self.buffer_count ]; + self.virtio_network_buffers = vec![[0; 1514]; self.queue_size.into()]; + self.rx_free_descriptors = vec![true; self.buffer_count]; self.tx_free_descriptors = vec![true; self.buffer_count]; @@ -299,7 +308,10 @@ impl VirtioNetInner { if let Ok(header_idx) = Self::get_free_idx(&mut self.rx_free_descriptors) { let buffer_idx = header_idx + self.buffer_count; - let buffer_addr = buffer.as_ptr() as u64; + // let buffer_addr = buffer.as_ptr() as u64; + + // Use the shared memory region + let buffer_addr = self.virtio_network_buffers[buffer_idx].as_ptr() as u64; // Store it so it isn't dropped self.rx_buffers[header_idx] = Some(buffer); @@ -368,7 +380,12 @@ impl VirtioNetInner { if let Ok(header_idx) = Self::get_free_idx(&mut self.tx_free_descriptors) { let buffer_idx = header_idx + self.buffer_count; - let buffer_addr = buffer.as_ptr() as u64; + + // Copy the packet into the shared memory region + let a = buffer.as_slice(); + self.virtio_network_buffers[header_idx].copy_from_slice(a); + + let buffer_addr = self.virtio_network_buffers[header_idx].as_ptr() as u64; // Store it so it isn't dropped self.tx_buffers[header_idx] = Some(buffer); @@ -431,7 +448,12 @@ impl VirtioNetInner { let header_descriptor = &rx_q.descriptors[used_element.id as usize]; let buffer_descriptor = &rx_q.descriptors[header_descriptor.next as usize]; - if let Some(buffer) = self.rx_buffers[used_element.id as usize].take() { + if let Some(mut buffer) = self.rx_buffers[used_element.id as usize].take() { + // Copy rx packet from shared memory region to buffer + buffer.copy_from_slice( + &self.virtio_network_buffers[header_descriptor.next as usize].as_slice(), + ); + // Processed packets are "collected" collect.push_back(buffer); new_packets_count += 1; From bda1f72074813fd5b2a93a6d6cc7524d36fd04c2 Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Sun, 26 Sep 2021 20:03:28 -0700 Subject: [PATCH 14/15] Changed frontend mmio to use offsets --- .../virtio_backend/src/virtio_backend.rs | 5 +---- .../virtio_backend/src/virtual_queue.rs | 11 +++++++--- lib/devices/virtio_backend/src/defs.rs | 4 ++-- lib/devices/virtio_net_mmio/src/lib.rs | 20 +++++++++++++------ 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/domains/sys/driver/virtio_backend/src/virtio_backend.rs b/domains/sys/driver/virtio_backend/src/virtio_backend.rs index 3c2f59dd..376ea793 100644 --- a/domains/sys/driver/virtio_backend/src/virtio_backend.rs +++ b/domains/sys/driver/virtio_backend/src/virtio_backend.rs @@ -10,15 +10,12 @@ use interface::{ rref::{RRef, RRefDeque}, }; use virtio_backend_trusted::defs::{ - Buffer, BufferPtr, BATCH_SIZE, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, + Buffer, BufferPtr, BATCH_SIZE, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, SHARED_MEMORY_REGION_PTR, }; use virtio_device::defs::VirtqUsedElement; use crate::{defs::VirtioQueueConfig, virtual_queue::VirtualQueue}; -/// fb: Indicates that this is used in the frontend to backend path -/// bf: Indicated that this is used in the backend to frontend path - pub struct VirtioBackend { /// A copy of the queue_config's device status device_status: u8, diff --git a/domains/sys/driver/virtio_backend/src/virtual_queue.rs b/domains/sys/driver/virtio_backend/src/virtual_queue.rs index 692993d2..609fbdd4 100644 --- a/domains/sys/driver/virtio_backend/src/virtual_queue.rs +++ b/domains/sys/driver/virtio_backend/src/virtual_queue.rs @@ -2,7 +2,7 @@ use core::{mem, ptr::read_volatile}; use alloc::{collections::VecDeque, slice, vec::Vec}; use hashbrown::HashMap; -use virtio_backend_trusted::defs::{BufferPtr, BATCH_SIZE}; +use virtio_backend_trusted::defs::{BufferPtr, BATCH_SIZE, SHARED_MEMORY_REGION_PTR}; use virtio_device::defs::{ VirtQueue, VirtqAvailablePacked, VirtqDescriptor, VirtqUsedElement, VirtqUsedPacked, }; @@ -163,8 +163,13 @@ impl VirtualQueue { if descriptor.len == 1514 { // Add it to the device and break - self.buffer_deque.push_back(descriptor.addr as BufferPtr); - self.buffer_map.insert(descriptor.addr, chain_header_idx); + + // descriptor.addr is an offset, convert it to an address + let addr = (unsafe { *SHARED_MEMORY_REGION_PTR } as usize + + descriptor.addr as usize) as u64; + + self.buffer_deque.push_back(addr as BufferPtr); + self.buffer_map.insert(addr, chain_header_idx); break; } else { // Try the next descriptor diff --git a/lib/devices/virtio_backend/src/defs.rs b/lib/devices/virtio_backend/src/defs.rs index 9b3d549a..9733aa03 100644 --- a/lib/devices/virtio_backend/src/defs.rs +++ b/lib/devices/virtio_backend/src/defs.rs @@ -6,8 +6,8 @@ pub const BATCH_SIZE: usize = 32; pub const MMIO_ADDRESS: *mut VirtioPciCommonConfig = 0x100000 as *mut VirtioPciCommonConfig; pub const DEVICE_NOTIFY: *mut usize = (0x100000 - size_of::()) as *mut usize; -pub const SHARED_MEMORY_REGION_PTR: *mut usize = - (0x100000 + size_of::() + 0x1000) as *mut usize; +pub const SHARED_MEMORY_REGION_PTR: *mut *mut Buffer = + (0x100000 + size_of::() + 0x1000) as *mut *mut Buffer; pub type Buffer = [u8; 1514]; pub type BufferPtr = *const Buffer; diff --git a/lib/devices/virtio_net_mmio/src/lib.rs b/lib/devices/virtio_net_mmio/src/lib.rs index 78b38489..e5fbeb7e 100644 --- a/lib/devices/virtio_net_mmio/src/lib.rs +++ b/lib/devices/virtio_net_mmio/src/lib.rs @@ -26,7 +26,7 @@ use hashbrown::HashMap; use interface::rref::{RRef, RRefDeque}; use libsyscalls::syscalls::sys_yield; use spin::Mutex; -use virtio_backend_trusted::defs::DeviceNotificationType; +use virtio_backend_trusted::defs::{DeviceNotificationType, SHARED_MEMORY_REGION_PTR}; use virtio_backend_trusted::device_notify; use virtio_device::defs::{ VirtQueue, VirtqAvailable, VirtqAvailablePacked, VirtqDescriptor, VirtqUsed, VirtqUsedElement, @@ -239,6 +239,10 @@ impl VirtioNetInner { ]; self.virtio_network_buffers = vec![[0; 1514]; self.queue_size.into()]; + // Update the ptr + unsafe { + *SHARED_MEMORY_REGION_PTR = self.virtio_network_buffers.as_mut_ptr(); + } self.rx_free_descriptors = vec![true; self.buffer_count]; self.tx_free_descriptors = vec![true; self.buffer_count]; @@ -312,6 +316,7 @@ impl VirtioNetInner { // Use the shared memory region let buffer_addr = self.virtio_network_buffers[buffer_idx].as_ptr() as u64; + let buffer_offset = buffer_addr - self.virtio_network_buffers.as_ptr() as u64; // Store it so it isn't dropped self.rx_buffers[header_idx] = Some(buffer); @@ -328,7 +333,7 @@ impl VirtioNetInner { }; // Actual Buffer rx_q.descriptors[buffer_idx] = VirtqDescriptor { - addr: buffer_addr, + addr: buffer_offset, len: 1514, flags: 2, next: 0, @@ -386,6 +391,7 @@ impl VirtioNetInner { self.virtio_network_buffers[header_idx].copy_from_slice(a); let buffer_addr = self.virtio_network_buffers[header_idx].as_ptr() as u64; + let buffer_offset = buffer_addr - self.virtio_network_buffers.as_ptr() as u64; // Store it so it isn't dropped self.tx_buffers[header_idx] = Some(buffer); @@ -397,7 +403,7 @@ impl VirtioNetInner { next: buffer_idx as u16, }; tx_q.descriptors[buffer_idx] = VirtqDescriptor { - addr: buffer_addr, + addr: buffer_offset, len: 1514, flags: 0, next: 0, @@ -408,9 +414,11 @@ impl VirtioNetInner { .ring(tx_q.available.data.idx % self.queue_size) = header_idx as u16; tx_q.available.data.idx = tx_q.available.data.idx.wrapping_add(1); - unsafe { - self.mmio.queue_notify(1, 1); - } + // unsafe { + // self.mmio.queue_notify(1, 1); + // } + device_notify(DeviceNotificationType::QueueUpdated); + return Ok(()); } else { return Err(buffer); From 7a884b8ba89c027c812192c74a9d670b7790bc3b Mon Sep 17 00:00:00 2001 From: Connor Zwick Date: Sun, 3 Oct 2021 20:23:52 -0700 Subject: [PATCH 15/15] Fixed safe unsafe spit --- domains/Cargo.lock | 2 +- domains/sys/driver/virtio_backend/src/defs.rs | 31 ------- domains/sys/driver/virtio_backend/src/main.rs | 69 ++++------------ .../virtio_backend/src/virtio_backend.rs | 18 ++--- domains/sys/init/src/main.rs | 5 +- interface/Cargo.lock | 81 ------------------- interface/Cargo.toml | 2 - interface/src/domain_create.rs | 6 +- kernel/Cargo.lock | 2 +- lib/devices/virtio_backend/Cargo.toml | 1 + lib/devices/virtio_backend/src/defs.rs | 40 +++++++-- lib/devices/virtio_backend/src/lib.rs | 72 ++++++++++++++++- .../virtio_backend/src/virtual_queue.rs | 10 +-- tools/rv6-mkfs/Cargo.lock | 81 ------------------- 14 files changed, 137 insertions(+), 283 deletions(-) delete mode 100644 domains/sys/driver/virtio_backend/src/defs.rs rename {domains/sys/driver => lib/devices}/virtio_backend/src/virtual_queue.rs (94%) diff --git a/domains/Cargo.lock b/domains/Cargo.lock index 1f05c64c..fbfaed4d 100644 --- a/domains/Cargo.lock +++ b/domains/Cargo.lock @@ -334,7 +334,6 @@ dependencies = [ "spin 0.5.3", "syscalls", "unwind", - "virtio_backend_trusted", ] [[package]] @@ -1026,6 +1025,7 @@ version = "0.1.0" dependencies = [ "console", "hashbrown 0.7.2", + "interface", "libsyscalls", "libtime", "malloc", diff --git a/domains/sys/driver/virtio_backend/src/defs.rs b/domains/sys/driver/virtio_backend/src/defs.rs deleted file mode 100644 index e9738588..00000000 --- a/domains/sys/driver/virtio_backend/src/defs.rs +++ /dev/null @@ -1,31 +0,0 @@ -use virtio_device::defs::{VirtQueue, VirtqAvailablePacked, VirtqUsedPacked}; - -#[derive(Debug)] -pub struct VirtioQueueConfig { - pub queue_index: u16, - pub queue_size: u16, - pub queue_enable: bool, - pub queue_descriptor: u64, - pub queue_driver: u64, - pub queue_device: u64, - - /// The next idx to process for the driver queue - pub driver_idx: u16, - - /// The next idx to process for the device queue - pub device_idx: u16, -} - -impl VirtioQueueConfig { - pub fn get_driver_queue(&mut self) -> &mut VirtqAvailablePacked { - unsafe { - return &mut *(self.queue_driver as *mut VirtqAvailablePacked); - } - } - - pub fn get_device_queue(&mut self) -> &mut VirtqUsedPacked { - unsafe { - return &mut *(self.queue_driver as *mut VirtqUsedPacked); - } - } -} diff --git a/domains/sys/driver/virtio_backend/src/main.rs b/domains/sys/driver/virtio_backend/src/main.rs index e213a001..97a48627 100644 --- a/domains/sys/driver/virtio_backend/src/main.rs +++ b/domains/sys/driver/virtio_backend/src/main.rs @@ -1,5 +1,6 @@ #![no_std] #![no_main] +// #![forbid(unsafe_code)] #![feature( box_syntax, const_fn, @@ -13,11 +14,8 @@ extern crate alloc; extern crate malloc; -mod defs; mod virtio_backend; -mod virtual_queue; -use crate::{defs::VirtioQueueConfig, virtio_backend::VirtioBackend}; use alloc::{boxed::Box, sync::Arc, vec, vec::Vec}; use console::{print, println}; use core::{ @@ -34,45 +32,24 @@ use libsyscalls::syscalls::{sys_backtrace, sys_create_thread, sys_yield}; use libtime::sys_ns_sleep; use spin::{Mutex, MutexGuard, Once}; use syscalls::{Heap, Syscall}; -use virtio_backend_trusted::defs::{ - Buffer, DeviceNotificationType, BATCH_SIZE, DEVICE_NOTIFY, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, +use virtio_backend::VirtioBackend; +use virtio_backend_trusted::{ + defs::{ + Buffer, DeviceNotificationType, BATCH_SIZE, DEVICE_NOTIFY, MAX_SUPPORTED_QUEUES, + MMIO_ADDRESS, + }, + get_device_notifications, get_thread_arguments, VirtioBackendThreadArguments, THREAD_ARGUMENTS, }; +use virtio_backend_trusted::{initialize_device_config_space, virtual_queue::VirtualQueue}; use virtio_device::{defs::VirtQueue, VirtioPciCommonConfig}; use virtio_net_mmio_device::VirtioNetworkDeviceConfig; -use virtual_queue::VirtualQueue; -struct VirtioBackendThreadArguments { - net: Box, -} - -static mut THREAD_ARGUMENTS: Option = None; - -fn initialize_device_config_space() { - unsafe { - write_volatile(DEVICE_NOTIFY, 0); +pub extern "C" fn virtio_backend() { + // Retrieve Thread Arguments + let args = get_thread_arguments(); - write_volatile( - MMIO_ADDRESS, - VirtioPciCommonConfig { - device_feature_select: 0, - device_feature: 0, - driver_feature_select: 0, - driver_feature: 0, - msix_config: 0, - num_queues: MAX_SUPPORTED_QUEUES, - device_status: 0, - config_generation: 0, - queue_select: 0, - queue_size: 256, - queue_msix_vector: 0, - queue_enable: 0, - queue_notify_off: 0, - queue_desc: 0, - queue_driver: 0, - queue_device: 0, - }, - ); - } + initialize_device_config_space(); + process_notifications(args.net); } fn process_notifications(net: Box) -> ! { @@ -82,9 +59,9 @@ fn process_notifications(net: Box) -> ! { // Check device for processed buffers and move to queues backend.update_queues(); - let dn = unsafe { read_volatile(DEVICE_NOTIFY) }; + let notification = get_device_notifications(); - match DeviceNotificationType::from_value(dn) { + match notification { DeviceNotificationType::DeviceConfigurationUpdated => { backend.handle_device_config_update(); } @@ -94,24 +71,10 @@ fn process_notifications(net: Box) -> ! { DeviceNotificationType::None => {} } - if dn != 0 { - unsafe { - write_volatile(DEVICE_NOTIFY, 0); - } - } - sys_yield(); } } -extern "C" fn virtio_backend() { - // Retrieve Thread Arguments - let args = unsafe { THREAD_ARGUMENTS.take().unwrap() }; - - initialize_device_config_space(); - process_notifications(args.net); -} - #[no_mangle] pub fn trusted_entry( s: Box, diff --git a/domains/sys/driver/virtio_backend/src/virtio_backend.rs b/domains/sys/driver/virtio_backend/src/virtio_backend.rs index 376ea793..8117bc92 100644 --- a/domains/sys/driver/virtio_backend/src/virtio_backend.rs +++ b/domains/sys/driver/virtio_backend/src/virtio_backend.rs @@ -1,21 +1,21 @@ -use core::ptr::read_volatile; - use alloc::collections::VecDeque; use alloc::vec; use alloc::{boxed::Box, vec::Vec}; use console::println; +use core::ptr::read_volatile; use hashbrown::HashMap; use interface::{ net::Net, rref::{RRef, RRefDeque}, }; use virtio_backend_trusted::defs::{ - Buffer, BufferPtr, BATCH_SIZE, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, SHARED_MEMORY_REGION_PTR, + Buffer, BufferPtr, VirtioQueueConfig, BATCH_SIZE, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, + SHARED_MEMORY_REGION_PTR, }; +use virtio_backend_trusted::virtual_queue::VirtualQueue; +use virtio_backend_trusted::{copy_buffer_into_rref, copy_rref_into_buffer}; use virtio_device::defs::VirtqUsedElement; -use crate::{defs::VirtioQueueConfig, virtual_queue::VirtualQueue}; - pub struct VirtioBackend { /// A copy of the queue_config's device status device_status: u8, @@ -138,9 +138,7 @@ impl VirtioBackend { if !rx { // If it's tx we need to copy the buffer's contents into the RRef - unsafe { - core::ptr::copy(buffer, rref.as_ptr() as *mut Buffer, 1); - } + copy_buffer_into_rref(&buffer, &rref); } self.buffer_rref_map @@ -164,9 +162,7 @@ impl VirtioBackend { while let Some(rref) = collect.pop_front() { if let Some(buffer) = self.buffer_rref_map.remove(&(rref.as_ptr() as u64)) { if rx { - unsafe { - core::ptr::copy(rref.as_ptr() as *mut Buffer, buffer as *mut Buffer, 1); - } + copy_rref_into_buffer(&rref, buffer as BufferPtr); } queue.mark_buffers_as_complete(&[buffer as BufferPtr]); diff --git a/domains/sys/init/src/main.rs b/domains/sys/init/src/main.rs index 003c52a4..0f0baa3c 100644 --- a/domains/sys/init/src/main.rs +++ b/domains/sys/init/src/main.rs @@ -20,7 +20,6 @@ use interface::rref::RRefVec; use libsyscalls::syscalls::{ sys_backtrace, sys_create_thread, sys_readch_kbd, sys_recv_int, sys_yield, }; -use virtio_backend_trusted::defs::VirtioMMIOConfiguration; #[cfg(feature = "test_guard_page")] fn test_stack_exhaustion() -> u64 { @@ -255,9 +254,7 @@ pub fn trusted_entry( let (_, net) = proxy .as_domain_create_CreateVirtioNetMMIO() - .create_domain_virtio_net_mmio(Box::new(VirtioMMIOConfiguration { - configuration_address: 0x100000, - })); + .create_domain_virtio_net_mmio(); #[cfg(all(not(feature = "shadow"), not(feature = "virtnet")))] let (_, net) = proxy.as_create_ixgbe().create_domain_ixgbe(pci.pci_clone()); diff --git a/interface/Cargo.lock b/interface/Cargo.lock index 88845724..6b00af05 100644 --- a/interface/Cargo.lock +++ b/interface/Cargo.lock @@ -34,12 +34,6 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - [[package]] name = "console" version = "0.1.0" @@ -71,15 +65,8 @@ dependencies = [ "pci_driver", "spin", "syscalls", - "virtio_backend_trusted", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libsyscalls" version = "0.1.0" @@ -90,32 +77,6 @@ dependencies = [ "syscalls", ] -[[package]] -name = "libtime" -version = "0.1.0" -dependencies = [ - "console", - "libsyscalls", -] - -[[package]] -name = "log" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "malloc" -version = "0.1.0" -dependencies = [ - "libsyscalls", - "slabmalloc", - "spin", -] - [[package]] name = "num-derive" version = "0.3.2" @@ -179,13 +140,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "slabmalloc" -version = "0.7.0" -dependencies = [ - "log", -] - [[package]] name = "spin" version = "0.5.3" @@ -216,38 +170,3 @@ name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "virtio_backend_trusted" -version = "0.1.0" -dependencies = [ - "console", - "hashbrown", - "libsyscalls", - "libtime", - "malloc", - "spin", - "virtio_device", - "volatile_accessor", -] - -[[package]] -name = "virtio_device" -version = "0.1.0" -dependencies = [ - "console", - "libsyscalls", - "libtime", - "malloc", - "volatile_accessor", -] - -[[package]] -name = "volatile_accessor" -version = "0.1.0" -dependencies = [ - "lazy_static", - "proc-macro2", - "quote", - "syn", -] diff --git a/interface/Cargo.toml b/interface/Cargo.toml index 1743650e..b2d7fc4f 100644 --- a/interface/Cargo.toml +++ b/interface/Cargo.toml @@ -16,7 +16,5 @@ pci_driver = { path = "../lib/core/interfaces/dev/pci/pci_driver/", version = "0 console = { path = "../lib/core/console", version = "0.1.0" } spin = { path = "../lib/core/spin-rs" } hashbrown = "0.7.2" -virtio_backend_trusted = { path = "../lib/devices/virtio_backend" } - diff --git a/interface/src/domain_create.rs b/interface/src/domain_create.rs index 95d8d3dd..b38dfb58 100644 --- a/interface/src/domain_create.rs +++ b/interface/src/domain_create.rs @@ -13,7 +13,6 @@ use crate::{ use alloc::boxed::Box; use alloc::sync::Arc; use syscalls::{Domain, Heap, Interrupt}; -use virtio_backend_trusted::defs::VirtioMMIOConfiguration; #[domain_create(path = "dom_proxy")] pub trait CreateProxy { @@ -96,10 +95,7 @@ pub trait CreateVirtioBackend: Send + Sync { #[domain_create(path = "virtio_net_mmio")] pub trait CreateVirtioNetMMIO: Send + Sync { - fn create_domain_virtio_net_mmio( - &self, - config: Box, - ) -> (Box, Box); + fn create_domain_virtio_net_mmio(&self) -> (Box, Box); } #[domain_create(path = "net_shadow")] diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 270a4d9a..4aeb5176 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -298,7 +298,6 @@ dependencies = [ "spin 0.5.3", "syscalls", "unwind", - "virtio_backend_trusted", ] [[package]] @@ -742,6 +741,7 @@ version = "0.1.0" dependencies = [ "console", "hashbrown 0.7.2", + "interface", "libsyscalls", "libtime", "malloc", diff --git a/lib/devices/virtio_backend/Cargo.toml b/lib/devices/virtio_backend/Cargo.toml index a4028b5d..0a01c338 100644 --- a/lib/devices/virtio_backend/Cargo.toml +++ b/lib/devices/virtio_backend/Cargo.toml @@ -13,6 +13,7 @@ console = { path = "../../../lib/core/console" } malloc = { path = "../../../lib/core/malloc" } spin = { path = "../../../lib/core/spin-rs" } volatile_accessor = { path = "../../../lib/external/volatile_accessor" } +interface = { path = "../../../interface/generated" } virtio_device = { path = "../virtio" } diff --git a/lib/devices/virtio_backend/src/defs.rs b/lib/devices/virtio_backend/src/defs.rs index 9733aa03..1d3be1e7 100644 --- a/lib/devices/virtio_backend/src/defs.rs +++ b/lib/devices/virtio_backend/src/defs.rs @@ -1,5 +1,8 @@ use core::mem::size_of; -use virtio_device::VirtioPciCommonConfig; +use virtio_device::{ + defs::{VirtqAvailablePacked, VirtqUsedPacked}, + VirtioPciCommonConfig, +}; pub const MAX_SUPPORTED_QUEUES: u16 = 2; pub const BATCH_SIZE: usize = 32; @@ -12,10 +15,7 @@ pub const SHARED_MEMORY_REGION_PTR: *mut *mut Buffer = pub type Buffer = [u8; 1514]; pub type BufferPtr = *const Buffer; -pub struct VirtioMMIOConfiguration { - pub configuration_address: usize, -} - +#[derive(Debug, PartialEq)] pub enum DeviceNotificationType { None, DeviceConfigurationUpdated, @@ -40,3 +40,33 @@ impl DeviceNotificationType { } } } + +#[derive(Debug)] +pub struct VirtioQueueConfig { + pub queue_index: u16, + pub queue_size: u16, + pub queue_enable: bool, + pub queue_descriptor: u64, + pub queue_driver: u64, + pub queue_device: u64, + + /// The next idx to process for the driver queue + pub driver_idx: u16, + + /// The next idx to process for the device queue + pub device_idx: u16, +} + +impl VirtioQueueConfig { + pub fn get_driver_queue(&mut self) -> &mut VirtqAvailablePacked { + unsafe { + return &mut *(self.queue_driver as *mut VirtqAvailablePacked); + } + } + + pub fn get_device_queue(&mut self) -> &mut VirtqUsedPacked { + unsafe { + return &mut *(self.queue_driver as *mut VirtqUsedPacked); + } + } +} diff --git a/lib/devices/virtio_backend/src/lib.rs b/lib/devices/virtio_backend/src/lib.rs index 046ee0ba..98b18c54 100644 --- a/lib/devices/virtio_backend/src/lib.rs +++ b/lib/devices/virtio_backend/src/lib.rs @@ -9,12 +9,27 @@ )] pub mod defs; +pub mod virtual_queue; extern crate alloc; +use alloc::boxed::Box; use core::ptr::{read_volatile, write_volatile}; - -use defs::{DeviceNotificationType, DEVICE_NOTIFY}; +use defs::{ + Buffer, BufferPtr, DeviceNotificationType, DEVICE_NOTIFY, MAX_SUPPORTED_QUEUES, MMIO_ADDRESS, +}; +use interface::{net::Net, rref::RRef}; use libsyscalls::syscalls::sys_yield; +use virtio_device::VirtioPciCommonConfig; + +pub struct VirtioBackendThreadArguments { + pub net: Box, +} + +pub static mut THREAD_ARGUMENTS: Option = None; + +pub fn get_thread_arguments() -> VirtioBackendThreadArguments { + unsafe { THREAD_ARGUMENTS.take().unwrap() } +} pub fn device_notify(notification_type: DeviceNotificationType) { let value = notification_type.value(); @@ -30,3 +45,56 @@ pub fn device_notify(notification_type: DeviceNotificationType) { } } } + +pub fn initialize_device_config_space() { + unsafe { + write_volatile(DEVICE_NOTIFY, 0); + + write_volatile( + MMIO_ADDRESS, + VirtioPciCommonConfig { + device_feature_select: 0, + device_feature: 0, + driver_feature_select: 0, + driver_feature: 0, + msix_config: 0, + num_queues: MAX_SUPPORTED_QUEUES, + device_status: 0, + config_generation: 0, + queue_select: 0, + queue_size: 256, + queue_msix_vector: 0, + queue_enable: 0, + queue_notify_off: 0, + queue_desc: 0, + queue_driver: 0, + queue_device: 0, + }, + ); + } +} + +pub fn get_device_notifications() -> DeviceNotificationType { + let dn = unsafe { read_volatile(DEVICE_NOTIFY) }; + + if dn != DeviceNotificationType::None.value() { + // Clear the notification + unsafe { + write_volatile(DEVICE_NOTIFY, 0); + } + } + + DeviceNotificationType::from_value(dn) +} + +pub fn copy_buffer_into_rref(buffer: &BufferPtr, rref: &RRef) { + unsafe { + core::ptr::copy(*buffer, rref.as_ptr() as *mut Buffer, 1); + } +} + +pub fn copy_rref_into_buffer(rref: &RRef, buffer: BufferPtr) { + unsafe { + core::ptr::copy(rref.as_ptr() as *mut Buffer, buffer as *mut Buffer, 1); + } +} diff --git a/domains/sys/driver/virtio_backend/src/virtual_queue.rs b/lib/devices/virtio_backend/src/virtual_queue.rs similarity index 94% rename from domains/sys/driver/virtio_backend/src/virtual_queue.rs rename to lib/devices/virtio_backend/src/virtual_queue.rs index 609fbdd4..0d7c21b5 100644 --- a/domains/sys/driver/virtio_backend/src/virtual_queue.rs +++ b/lib/devices/virtio_backend/src/virtual_queue.rs @@ -1,10 +1,8 @@ -use core::{mem, ptr::read_volatile}; - -use alloc::{collections::VecDeque, slice, vec::Vec}; +use crate::defs::{BufferPtr, BATCH_SIZE, SHARED_MEMORY_REGION_PTR}; +use alloc::{collections::VecDeque, slice}; use hashbrown::HashMap; -use virtio_backend_trusted::defs::{BufferPtr, BATCH_SIZE, SHARED_MEMORY_REGION_PTR}; use virtio_device::defs::{ - VirtQueue, VirtqAvailablePacked, VirtqDescriptor, VirtqUsedElement, VirtqUsedPacked, + VirtqAvailablePacked, VirtqDescriptor, VirtqUsedElement, VirtqUsedPacked, }; #[derive(Debug)] @@ -151,7 +149,7 @@ impl VirtualQueue { while self.driver_queue.previous_idx != *self.driver_queue.idx() && self.buffer_deque.len() < BATCH_SIZE { - let idx = (self.driver_queue.previous_idx % self.queue_size); + let idx = self.driver_queue.previous_idx % self.queue_size; let chain_header_idx = *self.driver_queue.ring(idx); let descriptors = self.descriptor_queue.get_descriptors(); diff --git a/tools/rv6-mkfs/Cargo.lock b/tools/rv6-mkfs/Cargo.lock index 92c7575d..7102abc6 100644 --- a/tools/rv6-mkfs/Cargo.lock +++ b/tools/rv6-mkfs/Cargo.lock @@ -34,12 +34,6 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - [[package]] name = "console" version = "0.1.0" @@ -73,15 +67,8 @@ dependencies = [ "spin", "syscalls", "unwind", - "virtio_backend_trusted", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libsyscalls" version = "0.1.0" @@ -92,32 +79,6 @@ dependencies = [ "syscalls", ] -[[package]] -name = "libtime" -version = "0.1.0" -dependencies = [ - "console", - "libsyscalls", -] - -[[package]] -name = "log" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "malloc" -version = "0.1.0" -dependencies = [ - "libsyscalls", - "slabmalloc", - "spin", -] - [[package]] name = "num-derive" version = "0.3.3" @@ -191,13 +152,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "slabmalloc" -version = "0.7.0" -dependencies = [ - "log", -] - [[package]] name = "spin" version = "0.5.3" @@ -236,38 +190,3 @@ dependencies = [ "libsyscalls", "syscalls", ] - -[[package]] -name = "virtio_backend_trusted" -version = "0.1.0" -dependencies = [ - "console", - "hashbrown", - "libsyscalls", - "libtime", - "malloc", - "spin", - "virtio_device", - "volatile_accessor", -] - -[[package]] -name = "virtio_device" -version = "0.1.0" -dependencies = [ - "console", - "libsyscalls", - "libtime", - "malloc", - "volatile_accessor", -] - -[[package]] -name = "volatile_accessor" -version = "0.1.0" -dependencies = [ - "lazy_static", - "proc-macro2", - "quote", - "syn", -]