diff --git a/src/arch/x86_64/kernel/mmio.rs b/src/arch/x86_64/kernel/mmio.rs index 4aa9fa9ba4..9b62e47be9 100644 --- a/src/arch/x86_64/kernel/mmio.rs +++ b/src/arch/x86_64/kernel/mmio.rs @@ -1,3 +1,4 @@ +use alloc::string::String; use alloc::vec::Vec; use core::{ptr, str}; @@ -11,6 +12,7 @@ use crate::arch::x86_64::mm::{paging, PhysAddr}; use crate::drivers::net::virtio_net::VirtioNetDriver; use crate::drivers::virtio::transport::mmio as mmio_virtio; use crate::drivers::virtio::transport::mmio::{DevId, MmioRegisterLayout, VirtioDriver}; +use crate::env; pub const MAGIC_VALUE: u32 = 0x74726976; @@ -34,9 +36,88 @@ impl MmioDriver { } } -/// Tries to find the network device within the specified address range. -/// Returns a reference to it within the Ok() if successful or an Err() on failure. -pub fn detect_network() -> Result<&'static mut MmioRegisterLayout, &'static str> { +fn check_linux_args( + linux_mmio: &'static [String], +) -> Result<(&'static mut MmioRegisterLayout, u8), &'static str> { + let virtual_address = + crate::arch::mm::virtualmem::allocate(BasePageSize::SIZE as usize).unwrap(); + + for arg in linux_mmio { + trace!("check linux parameter: {}", arg); + + match arg.trim().trim_matches(char::from(0)).strip_prefix("4K@") { + Some(arg) => { + let v: Vec<&str> = arg.trim().split(':').collect(); + let without_prefix = v[0].trim_start_matches("0x"); + let current_address = usize::from_str_radix(without_prefix, 16).unwrap(); + let irq: u8 = v[1].parse::().unwrap(); + + trace!( + "try to detect MMIO device at physical address {:#X}", + current_address + ); + + let mut flags = PageTableEntryFlags::empty(); + flags.normal().writable(); + paging::map::( + virtual_address, + PhysAddr::from(current_address.align_down(BasePageSize::SIZE as usize)), + 1, + flags, + ); + + // Verify the first register value to find out if this is really an MMIO magic-value. + let mmio = unsafe { + &mut *(ptr::from_exposed_addr_mut::( + virtual_address.as_usize() + | (current_address & (BasePageSize::SIZE as usize - 1)), + )) + }; + + let magic = mmio.get_magic_value(); + let version = mmio.get_version(); + + if magic != MAGIC_VALUE { + trace!("It's not a MMIO-device at {mmio:p}"); + continue; + } + + if version != 2 { + trace!("Found a legacy device, which isn't supported"); + continue; + } + + // We found a MMIO-device (whose 512-bit address in this structure). + trace!("Found a MMIO-device at {mmio:p}"); + + // Verify the device-ID to find the network card + let id = mmio.get_device_id(); + + if id != DevId::VIRTIO_DEV_ID_NET { + trace!("It's not a network card at {mmio:p}"); + continue; + } + + crate::arch::mm::physicalmem::reserve( + PhysAddr::from(current_address.align_down(BasePageSize::SIZE as usize)), + BasePageSize::SIZE as usize, + ); + + return Ok((mmio, irq)); + } + _ => { + warn!("Inavlid prefix in {}", arg); + } + } + } + + // frees obsolete virtual memory region for MMIO devices + crate::arch::mm::virtualmem::deallocate(virtual_address, BasePageSize::SIZE as usize); + + Err("Network card not found!") +} + +fn guess_device() -> Result<(&'static mut MmioRegisterLayout, u8), &'static str> { // Trigger page mapping in the first iteration! let mut current_page = 0; let virtual_address = @@ -103,7 +184,7 @@ pub fn detect_network() -> Result<&'static mut MmioRegisterLayout, &'static str> //mmio.print_information(); - return Ok(mmio); + return Ok((mmio, IRQ_NUMBER)); } // frees obsolete virtual memory region for MMIO devices @@ -112,6 +193,18 @@ pub fn detect_network() -> Result<&'static mut MmioRegisterLayout, &'static str> Err("Network card not found!") } +/// Tries to find the network device within the specified address range. +/// Returns a reference to it within the Ok() if successful or an Err() on failure. +fn detect_network() -> Result<(&'static mut MmioRegisterLayout, u8), &'static str> { + let linux_mmio = env::mmio(); + + if linux_mmio.len() > 0 { + check_linux_args(linux_mmio) + } else { + guess_device() + } +} + pub(crate) fn register_driver(drv: MmioDriver) { unsafe { MMIO_DRIVERS.push(drv); @@ -125,12 +218,12 @@ pub(crate) fn get_network_driver() -> Option<&'static InterruptTicketMutex = Vec::with_capacity(self.mtu.into()); let num_buffers = { + const HEADER_SIZE: usize = mem::size_of::(); let packet = recv_data.pop().unwrap(); + + // drop packets with invalid packet size + if packet.len() < HEADER_SIZE { + transfer + .reuse() + .unwrap() + .provide() + .dispatch_await(Rc::clone(&self.recv_vqs.poll_queue), false); + + return None; + } + let header = unsafe { - const HEADER_SIZE: usize = mem::size_of::(); core::mem::transmute::<[u8; HEADER_SIZE], VirtioNetHdr>( packet[..HEADER_SIZE].try_into().unwrap(), ) @@ -681,7 +693,7 @@ impl VirtioNetDriver { } /// Returns the current status of the device, if VIRTIO_NET_F_STATUS - /// has been negotiated. Otherwise returns zero. + /// has been negotiated. Otherwise assumes an active device. #[cfg(not(feature = "pci"))] pub fn dev_status(&self) -> u16 { if self @@ -691,7 +703,7 @@ impl VirtioNetDriver { { self.dev_cfg.raw.get_status() } else { - 0 + u16::from(Status::VIRTIO_NET_S_LINK_UP) } } @@ -767,11 +779,8 @@ impl VirtioNetDriver { self.com_cfg.set_drv(); // Define minimal feature set - let min_feats: Vec = vec![ - Features::VIRTIO_F_VERSION_1, - Features::VIRTIO_NET_F_MAC, - Features::VIRTIO_NET_F_STATUS, - ]; + let min_feats: Vec = + vec![Features::VIRTIO_F_VERSION_1, Features::VIRTIO_NET_F_MAC]; let mut min_feat_set = FeatureSet::new(0); min_feat_set.set_features(&min_feats); @@ -779,6 +788,8 @@ impl VirtioNetDriver { // If wanted, push new features into feats here: // + // the link status can be announced + feats.push(Features::VIRTIO_NET_F_STATUS); // Indirect descriptors can be used feats.push(Features::VIRTIO_F_RING_INDIRECT_DESC); // MTU setting can be used diff --git a/src/env.rs b/src/env.rs index d85c5f152d..4ca18d5558 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,6 +1,6 @@ //! Central parsing of the command-line parameters. -use alloc::string::String; +use alloc::string::{String, ToString}; use alloc::vec::Vec; use core::str; @@ -27,6 +27,8 @@ struct Cli { freq: Option, env_vars: HashMap, args: Vec, + #[allow(dead_code)] + mmio: Vec, } /// Whether Hermit is running under the "uhyve" hypervisor. @@ -43,6 +45,7 @@ impl Default for Cli { RandomState::with_seeds(0, 0, 0, 0), ); let mut args = Vec::new(); + let mut mmio = Vec::new(); let words = shell_words::split(kernel::args().unwrap_or_default()).unwrap(); debug!("cli_words = {words:?}"); @@ -54,6 +57,12 @@ impl Default for Cli { }) }; while let Some(word) = words.next() { + if word.as_str().starts_with("virtio_mmio.device=") { + let v: Vec<&str> = word.as_str().split('=').collect(); + mmio.push(v[1].to_string()); + continue; + } + match word.as_str() { #[cfg(not(target_arch = "riscv64"))] "-freq" => { @@ -88,6 +97,8 @@ impl Default for Cli { freq, env_vars, args, + #[allow(dead_code)] + mmio, } } } @@ -111,3 +122,9 @@ pub fn vars() -> Iter<'static, String, String> { pub fn args() -> &'static [String] { CLI.get().unwrap().args.as_slice() } + +/// Returns the configuration of all mmio devices +#[allow(dead_code)] +pub fn mmio() -> &'static [String] { + CLI.get().unwrap().mmio.as_slice() +} diff --git a/src/mm/mod.rs b/src/mm/mod.rs index bfacc26c21..ca6bdfc385 100644 --- a/src/mm/mod.rs +++ b/src/mm/mod.rs @@ -81,7 +81,7 @@ pub(crate) fn init() { npage_2tables / (BasePageSize::SIZE as usize / mem::align_of::()) + 1; let reserved_space = (npage_3tables + npage_2tables + npage_1tables) * BasePageSize::SIZE as usize - + LargePageSize::SIZE as usize; + + 2 * LargePageSize::SIZE as usize; #[cfg(any(target_arch = "x86_64", target_arch = "riscv64"))] let has_1gib_pages = arch::processor::supports_1gib_pages(); let has_2mib_pages = arch::processor::supports_2mib_pages();