Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

collect configuration of mmio devices #968

Merged
merged 6 commits into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 100 additions & 7 deletions src/arch/x86_64/kernel/mmio.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use alloc::string::String;
use alloc::vec::Vec;
use core::{ptr, str};

Expand All @@ -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;

Expand All @@ -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::<u8>().unwrap();

trace!(
"try to detect MMIO device at physical address {:#X}",
current_address
);

let mut flags = PageTableEntryFlags::empty();
flags.normal().writable();
paging::map::<BasePageSize>(
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::<MmioRegisterLayout>(
virtual_address.as_usize()
| (current_address & (BasePageSize::SIZE as usize - 1)),
))
};

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

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

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

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

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

if id != DevId::VIRTIO_DEV_ID_NET {
trace!("It's not a network card at {mmio:p}");
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 =
Expand Down Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -125,12 +218,12 @@ pub(crate) fn get_network_driver() -> Option<&'static InterruptTicketMutex<Virti
pub(crate) fn init_drivers() {
// virtio: MMIO Device Discovery
without_interrupts(|| {
if let Ok(mmio) = detect_network() {
if let Ok((mmio, irq)) = detect_network() {
warn!(
"Found MMIO device, but we guess the interrupt number {}!",
IRQ_NUMBER
irq
);
if let Ok(VirtioDriver::Network(drv)) = mmio_virtio::init_device(mmio, IRQ_NUMBER) {
if let Ok(VirtioDriver::Network(drv)) = mmio_virtio::init_device(mmio, irq) {
register_driver(MmioDriver::VirtioNet(InterruptTicketMutex::new(drv)))
}
} else {
Expand Down
27 changes: 19 additions & 8 deletions src/drivers/net/virtio_net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,9 +582,21 @@ impl NetworkDriver for VirtioNetDriver {
if recv_data.len() == 1 {
let mut vec_data: Vec<u8> = Vec::with_capacity(self.mtu.into());
let num_buffers = {
const HEADER_SIZE: usize = mem::size_of::<VirtioNetHdr>();
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::<VirtioNetHdr>();
core::mem::transmute::<[u8; HEADER_SIZE], VirtioNetHdr>(
packet[..HEADER_SIZE].try_into().unwrap(),
)
Expand Down Expand Up @@ -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
Expand All @@ -691,7 +703,7 @@ impl VirtioNetDriver {
{
self.dev_cfg.raw.get_status()
} else {
0
u16::from(Status::VIRTIO_NET_S_LINK_UP)
}
}

Expand Down Expand Up @@ -767,18 +779,17 @@ impl VirtioNetDriver {
self.com_cfg.set_drv();

// Define minimal feature set
let min_feats: Vec<Features> = vec![
Features::VIRTIO_F_VERSION_1,
Features::VIRTIO_NET_F_MAC,
Features::VIRTIO_NET_F_STATUS,
];
let min_feats: Vec<Features> =
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);
let mut feats: Vec<Features> = min_feats;

// 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
Expand Down
19 changes: 18 additions & 1 deletion src/env.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -27,6 +27,8 @@ struct Cli {
freq: Option<u16>,
env_vars: HashMap<String, String, RandomState>,
args: Vec<String>,
#[allow(dead_code)]
mmio: Vec<String>,
}

/// Whether Hermit is running under the "uhyve" hypervisor.
Expand All @@ -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:?}");
Expand All @@ -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" => {
Expand Down Expand Up @@ -88,6 +97,8 @@ impl Default for Cli {
freq,
env_vars,
args,
#[allow(dead_code)]
mmio,
}
}
}
Expand All @@ -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()
}
2 changes: 1 addition & 1 deletion src/mm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ pub(crate) fn init() {
npage_2tables / (BasePageSize::SIZE as usize / mem::align_of::<usize>()) + 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();
Expand Down