diff --git a/applications/awkernel_shell/Cargo.toml b/applications/awkernel_shell/Cargo.toml index b26d7df57..14ecc0c42 100644 --- a/applications/awkernel_shell/Cargo.toml +++ b/applications/awkernel_shell/Cargo.toml @@ -9,6 +9,8 @@ edition = "2021" blisp = "0.4" log = "0.4" byteorder = { version = "1.0", default-features = false } +num-bigint = { version = "0.4", default-features = false } +num-traits = { version = "0.2", default-features = false } [dependencies.awkernel_async_lib] path = "../../awkernel_async_lib" diff --git a/applications/awkernel_shell/src/lib.rs b/applications/awkernel_shell/src/lib.rs index 916a2cdee..8e0d67bda 100644 --- a/applications/awkernel_shell/src/lib.rs +++ b/applications/awkernel_shell/src/lib.rs @@ -16,6 +16,8 @@ use awkernel_async_lib::{ use awkernel_lib::{console, sync::mutex::MCSNode, IS_STD}; use blisp::{embedded, runtime::FFI}; use core::time::Duration; +use num_bigint::BigInt; +use num_traits::ToPrimitive; const SERVICE_NAME: &str = "[Awkernel] shell"; @@ -48,6 +50,7 @@ async fn console_handler() -> TaskResult { Box::new(TaskFfi), Box::new(InterruptFfi), Box::new(IfconfigFfi), + Box::new(NetdumpFfi), Box::new(RebootFfi), Box::new(ShutdownFfi), ]; @@ -169,6 +172,9 @@ const CODE: &str = "(export factorial (n) (Pure (-> (Int) Int)) (export ifconfig () (IO (-> () [])) (ifconfig_ffi)) +(export netdump (interface_id) (IO (-> (Int) [])) + (netdump_ffi interface_id)) + (export reboot () (IO (-> () [])) (reboot_ffi)) @@ -192,6 +198,7 @@ fn help_ffi() { lines.push_str("(task) ; print tasks\r\n"); lines.push_str("(interrupt) ; print interrupt information\r\n"); lines.push_str("(ifconfig) ; print network interfaces\r\n"); + lines.push_str("(netdump if); dump device registers\r\n"); lines.push_str("(reboot) ; reboot x86_64 systems\r\n"); lines.push_str("(shutdown) ; power off x86_64 systems\r\n"); @@ -247,6 +254,18 @@ fn ifconfig_ffi() { } } +#[embedded] +fn netdump_ffi(interface_id: BigInt) { + let Some(interface_id) = interface_id.to_u64() else { + console::print("netdump failed: interface_id must fit in u64\r\n"); + return; + }; + + if let Err(e) = awkernel_lib::net::debug_dump_interface(interface_id) { + console::print(&format!("netdump failed: {e}\r\n")); + } +} + #[embedded] fn reboot_ffi() { #[cfg(all(target_arch = "x86_64", target_os = "none"))] diff --git a/awkernel_drivers/src/pcie/intel/igc.rs b/awkernel_drivers/src/pcie/intel/igc.rs index 8f7b69644..976a67dd9 100644 --- a/awkernel_drivers/src/pcie/intel/igc.rs +++ b/awkernel_drivers/src/pcie/intel/igc.rs @@ -315,6 +315,11 @@ impl NetDevice for Igc { .or(Err(net_device::NetDevError::DeviceError)) } + fn debug_dump(&self) { + let msg = self.inner.read().dump(); + log::debug!("igc: dump:\r\n{msg}"); + } + fn add_multicast_addr(&self, addr: &[u8; 6]) -> Result<(), net_device::NetDevError> { let mut inner = self.inner.write(); inner.multicast_addrs.add_addr(*addr); @@ -702,7 +707,7 @@ impl IgcInner { } } - fn dump(&self) { + fn dump(&self) -> alloc::string::String { let mut msg = alloc::string::String::new(); msg = format!("BDF: {}\r\n", self.info.get_bdf()); @@ -802,7 +807,7 @@ impl IgcInner { msg = format!("{msg}TDBAL{i}: {tdbal:#08x}\r\n"); } - log::debug!("igc: dump:\r\n{msg}"); + msg } #[inline(always)] diff --git a/awkernel_lib/src/net.rs b/awkernel_lib/src/net.rs index b8446a086..5a7f8f8b4 100644 --- a/awkernel_lib/src/net.rs +++ b/awkernel_lib/src/net.rs @@ -428,6 +428,28 @@ pub fn get_interface(interface_id: u64) -> Result { Ok(if_status) } +/// Emit debug state for the interface identified by `interface_id` via `log::debug!`. +/// +/// Returns [`NetManagerError::InvalidInterfaceID`] if no interface with that ID exists. +/// The NET_MANAGER read lock is held only to look up and clone the device reference; +/// the device dump runs outside that lock. +pub fn debug_dump_interface(interface_id: u64) -> Result<(), NetManagerError> { + let net_device = { + let net_manager = NET_MANAGER.read(); + + let if_net = net_manager + .interfaces + .get(&interface_id) + .ok_or(NetManagerError::InvalidInterfaceID)?; + + if_net.net_device.clone() + }; + + net_device.debug_dump(); + + Ok(()) +} + pub fn get_all_interface() -> Vec { let net_manager = NET_MANAGER.read(); diff --git a/awkernel_lib/src/net/net_device.rs b/awkernel_lib/src/net/net_device.rs index 17e2a9efa..f6a0685e2 100644 --- a/awkernel_lib/src/net/net_device.rs +++ b/awkernel_lib/src/net/net_device.rs @@ -220,6 +220,11 @@ pub trait NetDevice { Ok(()) } + /// Dump device-specific debug state on demand. + fn debug_dump(&self) { + log::warn!("debug_dump not implemented for this device"); + } + fn add_multicast_addr(&self, addr: &[u8; 6]) -> Result<(), NetDevError>; fn remove_multicast_addr(&self, addr: &[u8; 6]) -> Result<(), NetDevError>; }