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::<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 =
@@ -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<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 {
diff --git a/src/drivers/net/virtio_net.rs b/src/drivers/net/virtio_net.rs
index e3bbb17c7b..790cc32114 100644
--- a/src/drivers/net/virtio_net.rs
+++ b/src/drivers/net/virtio_net.rs
@@ -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(),
 							)
@@ -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<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);
@@ -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<u16>,
 	env_vars: HashMap<String, String, RandomState>,
 	args: Vec<String>,
+	#[allow(dead_code)]
+	mmio: Vec<String>,
 }
 
 /// 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::<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();