Skip to content

Commit

Permalink
Merge pull request #968 from stlankes/fc
Browse files Browse the repository at this point in the history
collect configuration of mmio devices
  • Loading branch information
mkroening authored Nov 9, 2023
2 parents 15c2b9c + f2a7eff commit b512910
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 17 deletions.
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

0 comments on commit b512910

Please sign in to comment.