diff --git a/src/arch/aarch64/kernel/interrupts.rs b/src/arch/aarch64/kernel/interrupts.rs index 492e7a0d91..e8ae22ad69 100644 --- a/src/arch/aarch64/kernel/interrupts.rs +++ b/src/arch/aarch64/kernel/interrupts.rs @@ -17,10 +17,6 @@ use memory_addresses::{PhysAddr, VirtAddr}; use crate::arch::aarch64::kernel::core_local::increment_irq_counter; use crate::arch::aarch64::kernel::scheduler::State; use crate::arch::aarch64::mm::paging::{self, BasePageSize, PageSize, PageTableEntryFlags}; -#[cfg(not(feature = "pci"))] -use crate::drivers::mmio::get_interrupt_handlers; -#[cfg(feature = "pci")] -use crate::drivers::pci::get_interrupt_handlers; use crate::drivers::{InterruptHandlerQueue, InterruptLine}; use crate::kernel::serial::handle_uart_interrupt; use crate::mm::{PageAlloc, PageRangeAllocator}; @@ -87,16 +83,17 @@ pub fn disable() { dmb(ISH); } -pub(crate) fn install_handlers() { +pub(crate) fn install_handlers( + old_handlers: HashMap, +) { let mut handlers: HashMap = HashMap::with_hasher(RandomState::with_seeds(0, 0, 0, 0)); - fn timer_handler() { debug!("Handle timer interrupt"); timer_interrupts::clear_active_and_set_next(); } - for (key, value) in get_interrupt_handlers().into_iter() { + for (key, value) in old_handlers.into_iter() { handlers.insert(key + SPI_START, value); } diff --git a/src/arch/aarch64/kernel/mmio.rs b/src/arch/aarch64/kernel/mmio.rs index 153bde370f..f3b889c2c6 100644 --- a/src/arch/aarch64/kernel/mmio.rs +++ b/src/arch/aarch64/kernel/mmio.rs @@ -1,8 +1,10 @@ use alloc::vec::Vec; use core::ptr::NonNull; +use ahash::RandomState; use align_address::Align; use arm_gic::{IntId, Trigger}; +use hashbrown::HashMap; #[cfg(any( feature = "virtio-console", feature = "virtio-fs", @@ -35,6 +37,7 @@ use crate::drivers::virtio::transport::mmio as mmio_virtio; use crate::drivers::virtio::transport::mmio::VirtioDriver; #[cfg(feature = "virtio-vsock")] use crate::drivers::vsock::VirtioVsockDriver; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; #[cfg(feature = "virtio-net")] use crate::executor::device::NETWORK_DEVICE; use crate::init_cell::InitCell; @@ -81,7 +84,11 @@ impl MmioDriver { } } -#[cfg(any(feature = "virtio-console", feature = "virtio-fs", feature = "virtio-vsock"))] +#[cfg(any( + feature = "virtio-console", + feature = "virtio-fs", + feature = "virtio-vsock" +))] pub(crate) fn register_driver(drv: MmioDriver) { MMIO_DRIVERS.with(|mmio_drivers| mmio_drivers.unwrap().push(drv)); } @@ -113,7 +120,7 @@ pub(crate) fn get_vsock_driver() -> Option<&'static InterruptTicketMutex) { without_interrupts(|| { let Some(fdt) = crate::env::fdt() else { error!("No device tree found, cannot initialize MMIO drivers"); @@ -187,13 +194,14 @@ pub fn init_drivers() { "Found {id:?} card at {mmio:p}, irq: {irq}, type: {irqtype}, flags: {irqflags}" ); - let drv = match mmio_virtio::init_device(mmio, irq.try_into().unwrap()) { - Ok(drv) => drv, - Err(err) => { - error!("{err}"); - continue; - } - }; + let drv = + match mmio_virtio::init_device(mmio, irq.try_into().unwrap(), handlers) { + Ok(drv) => drv, + Err(err) => { + error!("{err}"); + continue; + } + }; let mut gic = GIC.lock(); let Some(gic) = gic.as_mut() else { @@ -209,15 +217,19 @@ pub fn init_drivers() { } else { panic!("Invalid interrupt type"); }; - gic.set_interrupt_priority(virtio_irqid, Some(cpu_id), 0x00).unwrap(); + gic.set_interrupt_priority(virtio_irqid, Some(cpu_id), 0x00) + .unwrap(); if (irqflags & 0xf) == 4 || (irqflags & 0xf) == 8 { - gic.set_trigger(virtio_irqid, Some(cpu_id), Trigger::Level).unwrap(); + gic.set_trigger(virtio_irqid, Some(cpu_id), Trigger::Level) + .unwrap(); } else if (irqflags & 0xf) == 2 || (irqflags & 0xf) == 1 { - gic.set_trigger(virtio_irqid, Some(cpu_id), Trigger::Edge).unwrap(); + gic.set_trigger(virtio_irqid, Some(cpu_id), Trigger::Edge) + .unwrap(); } else { panic!("Invalid interrupt level!"); } - gic.enable_interrupt(virtio_irqid, Some(cpu_id), true).unwrap(); + gic.enable_interrupt(virtio_irqid, Some(cpu_id), true) + .unwrap(); match drv { #[cfg(feature = "virtio-console")] @@ -225,9 +237,9 @@ pub fn init_drivers() { InterruptTicketMutex::new(*drv), )), #[cfg(feature = "virtio-fs")] - VirtioDriver::Fs(drv) => register_driver(MmioDriver::VirtioFs( - InterruptTicketMutex::new(*drv), - )), + VirtioDriver::Fs(drv) => { + register_driver(MmioDriver::VirtioFs(InterruptTicketMutex::new(*drv))); + } #[cfg(feature = "virtio-net")] VirtioDriver::Net(drv) => *NETWORK_DEVICE.lock() = Some(*drv), #[cfg(feature = "virtio-vsock")] diff --git a/src/arch/riscv64/kernel/devicetree.rs b/src/arch/riscv64/kernel/devicetree.rs index c418b27e16..62dd5ab642 100644 --- a/src/arch/riscv64/kernel/devicetree.rs +++ b/src/arch/riscv64/kernel/devicetree.rs @@ -1,6 +1,8 @@ #[cfg(all(feature = "virtio", not(feature = "pci")))] use core::ptr::NonNull; +use ahash::RandomState; +use hashbrown::HashMap; use memory_addresses::PhysAddr; #[cfg(all(feature = "gem-net", not(feature = "pci")))] use memory_addresses::VirtAddr; @@ -42,6 +44,7 @@ use crate::drivers::virtio::transport::mmio as mmio_virtio; not(feature = "pci"), ))] use crate::drivers::virtio::transport::mmio::VirtioDriver; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; use crate::env; #[cfg(all(any(feature = "gem-net", feature = "virtio-net"), not(feature = "pci")))] use crate::executor::device::NETWORK_DEVICE; @@ -99,7 +102,9 @@ pub fn init() { /// Inits drivers based on the device tree /// This function should only be called once -pub fn init_drivers() { +pub fn init_drivers( + #[allow(unused)] handlers: &mut HashMap, +) { // TODO: Implement devicetree correctly if let Some(fdt) = env::fdt() { debug!("Init drivers using devicetree"); @@ -184,6 +189,7 @@ pub fn init_drivers() { irq.try_into().unwrap(), phy_addr, <[u8; 6]>::try_from(mac).expect("MAC with invalid length"), + handlers, ) { Ok(drv) => *NETWORK_DEVICE.lock() = Some(drv), Err(err) => error!("Could not initialize GEM driver: {err}"), @@ -252,7 +258,7 @@ pub fn init_drivers() { debug!("Found virtio {id:?} at {mmio:p}"); - match mmio_virtio::init_device(mmio, irq.try_into().unwrap()) { + match mmio_virtio::init_device(mmio, irq.try_into().unwrap(), handlers) { #[cfg(feature = "virtio-console")] Ok(VirtioDriver::Console(drv)) => { register_driver(MmioDriver::VirtioConsole( diff --git a/src/arch/riscv64/kernel/interrupts.rs b/src/arch/riscv64/kernel/interrupts.rs index 42e06114e9..47483e66a7 100644 --- a/src/arch/riscv64/kernel/interrupts.rs +++ b/src/arch/riscv64/kernel/interrupts.rs @@ -9,11 +9,7 @@ use riscv::interrupt::{Exception, Interrupt, Trap}; use riscv::register::{scause, sie, sip, sstatus, stval}; use trapframe::TrapFrame; -use crate::drivers::InterruptHandlerQueue; -#[cfg(not(feature = "pci"))] -use crate::drivers::mmio::get_interrupt_handlers; -#[cfg(feature = "pci")] -use crate::drivers::pci::get_interrupt_handlers; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; use crate::scheduler; /// Base address of the PLIC, only one access at the same time is allowed @@ -119,9 +115,9 @@ pub(crate) fn disable() { } /// Currently not needed because we use the trapframe crate -pub(crate) fn install_handlers() { - let handlers = get_interrupt_handlers(); - +pub(crate) fn install_handlers( + handlers: HashMap, +) { for irq_number in handlers.keys() { unsafe { let base_ptr = PLIC_BASE.lock(); diff --git a/src/arch/x86_64/kernel/interrupts.rs b/src/arch/x86_64/kernel/interrupts.rs index 6d39f076ef..47d5853be1 100644 --- a/src/arch/x86_64/kernel/interrupts.rs +++ b/src/arch/x86_64/kernel/interrupts.rs @@ -16,11 +16,7 @@ use crate::arch::x86_64::kernel::core_local::{core_scheduler, increment_irq_coun use crate::arch::x86_64::kernel::{apic, processor}; use crate::arch::x86_64::mm::paging::{BasePageSize, PageSize, page_fault_handler}; use crate::arch::x86_64::swapgs; -use crate::drivers::InterruptHandlerQueue; -#[cfg(not(feature = "pci"))] -use crate::drivers::mmio::get_interrupt_handlers; -#[cfg(feature = "pci")] -use crate::drivers::pci::get_interrupt_handlers; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; use crate::scheduler::{self, CoreId}; static IRQ_HANDLERS: OnceCell> = OnceCell::new(); @@ -163,8 +159,24 @@ pub(crate) fn install() { IRQ_NAMES.lock().insert(7, "FPU"); } -pub(crate) fn install_handlers() { - IRQ_HANDLERS.set(get_interrupt_handlers()).unwrap(); +pub(crate) fn install_handlers( + #[cfg_attr(not(feature = "pci"), expect(unused_mut))] mut handlers: HashMap< + InterruptLine, + InterruptHandlerQueue, + RandomState, + >, +) { + #[cfg(feature = "pci")] + { + use crate::kernel::serial; + add_irq_name(serial::SERIAL_IRQ, "COM1"); + handlers + .entry(serial::SERIAL_IRQ) + .or_default() + .push_back(serial::handle_interrupt); + } + + IRQ_HANDLERS.set(handlers).unwrap(); } fn handle_interrupt(stack_frame: ExceptionStackFrame, index: u8, _error_code: Option) { diff --git a/src/arch/x86_64/kernel/mmio.rs b/src/arch/x86_64/kernel/mmio.rs index db17b31098..57b792e232 100644 --- a/src/arch/x86_64/kernel/mmio.rs +++ b/src/arch/x86_64/kernel/mmio.rs @@ -3,8 +3,10 @@ use alloc::vec::Vec; use core::ptr::NonNull; use core::{ptr, str}; +use ahash::RandomState; use align_address::Align; use free_list::{PageLayout, PageRange}; +use hashbrown::HashMap; #[cfg(any( feature = "virtio-console", feature = "virtio-fs", @@ -36,6 +38,7 @@ use crate::drivers::virtio::transport::mmio as mmio_virtio; use crate::drivers::virtio::transport::mmio::VirtioDriver; #[cfg(feature = "virtio-vsock")] use crate::drivers::vsock::VirtioVsockDriver; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; use crate::env; #[cfg(any(feature = "rtl8139", feature = "virtio-net"))] use crate::executor::device::NETWORK_DEVICE; @@ -217,8 +220,12 @@ pub(crate) fn get_vsock_driver() -> Option<&'static InterruptTicketMutex, irq: u8) { - match mmio_virtio::init_device(mmio, irq) { +fn register_mmio( + mmio: VolatileRef<'static, DeviceRegisters>, + irq: u8, + handlers: &mut HashMap, +) { + match mmio_virtio::init_device(mmio, irq, handlers) { #[cfg(feature = "virtio-console")] Ok(VirtioDriver::Console(drv)) => { register_driver(MmioDriver::VirtioConsole(InterruptTicketMutex::new(*drv))); @@ -239,7 +246,9 @@ fn register_mmio(mmio: VolatileRef<'static, DeviceRegisters>, irq: u8) { } } -pub(crate) fn init_drivers() { +pub(crate) fn init_drivers( + handlers: &mut HashMap, +) { without_interrupts(|| { let layout = PageLayout::from_size(BasePageSize::SIZE as usize).unwrap(); let page_range = PageBox::new(layout).unwrap(); @@ -249,11 +258,11 @@ pub(crate) fn init_drivers() { if linux_mmio.is_empty() { for (mmio, irq) in guess_device(virtual_address) { - register_mmio(mmio, irq); + register_mmio(mmio, irq, handlers); } } else { for (mmio, irq) in check_linux_args(linux_mmio, virtual_address) { - register_mmio(mmio, irq); + register_mmio(mmio, irq, handlers); } } diff --git a/src/arch/x86_64/kernel/serial.rs b/src/arch/x86_64/kernel/serial.rs index 7d26526cd0..539ec18e4d 100644 --- a/src/arch/x86_64/kernel/serial.rs +++ b/src/arch/x86_64/kernel/serial.rs @@ -5,14 +5,10 @@ use hermit_sync::{InterruptTicketMutex, Lazy}; use uart_16550::backend::PioBackend; use uart_16550::{Config, Uart16550}; -#[cfg(feature = "pci")] -use crate::arch::x86_64::kernel::interrupts; -#[cfg(feature = "pci")] -use crate::drivers::InterruptLine; use crate::errno::Errno; #[cfg(feature = "pci")] -const SERIAL_IRQ: u8 = 4; +pub(crate) const SERIAL_IRQ: u8 = 4; static UART_DEVICE: Lazy> = Lazy::new(|| unsafe { InterruptTicketMutex::new(UartDevice::new()) }); @@ -79,21 +75,15 @@ impl Write for SerialDevice { } #[cfg(feature = "pci")] -pub(crate) fn get_serial_handler() -> (InterruptLine, fn()) { - fn serial_handler() { - let mut guard = UART_DEVICE.lock(); +pub(crate) fn handle_interrupt() { + let mut guard = UART_DEVICE.lock(); - while guard.uart.read_ready().unwrap() { - let mut buf = [0; 256]; - let n = guard.uart.read(&mut buf).unwrap(); - guard.buffer.write_all(&buf[..n]).unwrap(); - } - - drop(guard); - crate::console::CONSOLE_WAKER.lock().wake(); + while guard.uart.read_ready().unwrap() { + let mut buf = [0; 256]; + let n = guard.uart.read(&mut buf).unwrap(); + guard.buffer.write_all(&buf[..n]).unwrap(); } - interrupts::add_irq_name(SERIAL_IRQ, "COM1"); - - (SERIAL_IRQ, serial_handler) + drop(guard); + crate::console::CONSOLE_WAKER.lock().wake(); } diff --git a/src/drivers/console/mmio.rs b/src/drivers/console/mmio.rs index 7bef82ea95..d27f99fd29 100644 --- a/src/drivers/console/mmio.rs +++ b/src/drivers/console/mmio.rs @@ -1,18 +1,19 @@ +use ahash::RandomState; +use hashbrown::HashMap; use virtio::console::Config; use virtio::mmio::{DeviceRegisters, DeviceRegistersVolatileFieldAccess}; use volatile::VolatileRef; -use crate::drivers::InterruptLine; use crate::drivers::console::{ConsoleDevCfg, RxQueue, TxQueue, VirtioConsoleDriver}; use crate::drivers::virtio::error::VirtioError; use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; // Backend-dependent interface for Virtio console driver impl VirtioConsoleDriver { pub fn new( dev_id: u16, mut registers: VolatileRef<'static, DeviceRegisters>, - irq: InterruptLine, ) -> Result { let dev_cfg_raw: &'static Config = unsafe { &*registers @@ -37,7 +38,6 @@ impl VirtioConsoleDriver { com_cfg: ComCfg::new(registers), isr_stat, notif_cfg, - irq, recv_vq: RxQueue::new(), send_vq: TxQueue::new(), }) @@ -52,9 +52,11 @@ impl VirtioConsoleDriver { dev_id: u16, registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, + handlers: &mut HashMap, ) -> Result { - let mut drv = VirtioConsoleDriver::new(dev_id, registers, irq)?; - drv.init_dev().map_err(VirtioError::ConsoleDriver)?; + let mut drv = VirtioConsoleDriver::new(dev_id, registers)?; + drv.init_dev(handlers, Some(irq)) + .map_err(VirtioError::ConsoleDriver)?; drv.com_cfg.print_information(); Ok(drv) } diff --git a/src/drivers/console/mod.rs b/src/drivers/console/mod.rs index 01b0f731e5..343630d27e 100644 --- a/src/drivers/console/mod.rs +++ b/src/drivers/console/mod.rs @@ -18,7 +18,9 @@ cfg_select! { use alloc::vec::Vec; +use ahash::RandomState; use embedded_io::{ErrorType, Read, ReadReady, Write}; +use hashbrown::HashMap; use smallvec::SmallVec; use virtio::console::Config; use volatile::VolatileRef; @@ -40,7 +42,7 @@ use crate::drivers::virtio::virtqueue::split::SplitVq; use crate::drivers::virtio::virtqueue::{ AvailBufferToken, BufferElem, BufferType, UsedBufferToken, VirtQueue, Virtq, }; -use crate::drivers::{Driver, InterruptLine}; +use crate::drivers::{Driver, InterruptHandlerQueue, InterruptLine}; use crate::errno::Errno; use crate::mm::device_alloc::DeviceAlloc; @@ -262,17 +264,12 @@ pub(crate) struct VirtioConsoleDriver { pub(super) com_cfg: ComCfg, pub(super) isr_stat: IsrStatus, pub(super) notif_cfg: NotifCfg, - pub(super) irq: InterruptLine, pub(super) recv_vq: RxQueue, pub(super) send_vq: TxQueue, } impl Driver for VirtioConsoleDriver { - fn get_interrupt_number(&self) -> InterruptLine { - self.irq - } - fn get_name(&self) -> &'static str { "virtio" } @@ -307,7 +304,11 @@ impl VirtioConsoleDriver { self.com_cfg.set_failed(); } - pub fn init_dev(&mut self) -> Result<(), VirtioConsoleError> { + pub fn init_dev( + &mut self, + handlers: &mut HashMap, + irq: Option, + ) -> Result<(), VirtioConsoleError> { // Reset self.com_cfg.reset_dev(); @@ -372,6 +373,12 @@ impl VirtioConsoleDriver { // Interrupt for communicating that a sent packet left, is not needed self.send_vq.disable_notifs(); + handlers.entry(irq.unwrap()).or_default().push_back(|| { + if let Some(driver) = get_console_driver() { + driver.lock().handle_interrupt(); + }; + }); + // At this point the device is "live" self.com_cfg.drv_ok(); diff --git a/src/drivers/console/pci.rs b/src/drivers/console/pci.rs index c0422d77b3..131317392c 100644 --- a/src/drivers/console/pci.rs +++ b/src/drivers/console/pci.rs @@ -1,7 +1,10 @@ -use pci_types::CommandRegister; +use ahash::RandomState; +use hashbrown::HashMap; +use pci_types::{CommandRegister, InterruptLine}; use virtio::console::Config; use volatile::VolatileRef; +use crate::drivers::InterruptHandlerQueue; use crate::drivers::console::{ConsoleDevCfg, RxQueue, TxQueue, VirtioConsoleDriver}; use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; @@ -47,7 +50,6 @@ impl VirtioConsoleDriver { com_cfg, isr_stat: isr_cfg, notif_cfg, - irq: device.get_irq().unwrap(), recv_vq: RxQueue::new(), send_vq: TxQueue::new(), }) @@ -58,6 +60,7 @@ impl VirtioConsoleDriver { /// Returns a driver instance of VirtioConsoleDriver. pub(crate) fn init( device: &PciDevice, + handlers: &mut HashMap, ) -> Result { // enable bus master mode device.set_command(CommandRegister::BUS_MASTER_ENABLE); @@ -76,7 +79,7 @@ impl VirtioConsoleDriver { } }; - match drv.init_dev() { + match drv.init_dev(handlers, device.get_irq()) { Ok(()) => { info!( "Console device with id {:x}, has been initialized by driver!", diff --git a/src/drivers/fs/mmio.rs b/src/drivers/fs/mmio.rs index 3ae8b2db2a..d2e7a876bb 100644 --- a/src/drivers/fs/mmio.rs +++ b/src/drivers/fs/mmio.rs @@ -1,20 +1,21 @@ use alloc::vec::Vec; +use ahash::RandomState; +use hashbrown::HashMap; use virtio::fs::Config; use virtio::mmio::{DeviceRegisters, DeviceRegistersVolatileFieldAccess}; use volatile::VolatileRef; -use crate::drivers::InterruptLine; use crate::drivers::fs::{FsDevCfg, VirtioFsDriver}; use crate::drivers::virtio::error::VirtioError; use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; // Backend-dependent interface for Virtio fs driver impl VirtioFsDriver { pub fn new( dev_id: u16, mut registers: VolatileRef<'static, DeviceRegisters>, - irq: InterruptLine, ) -> Result { let dev_cfg_raw: &'static Config = unsafe { &*registers @@ -40,7 +41,6 @@ impl VirtioFsDriver { isr_stat, notif_cfg, vqueues: Vec::new(), - irq, }) } @@ -53,9 +53,11 @@ impl VirtioFsDriver { dev_id: u16, registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, + handlers: &mut HashMap, ) -> Result { - let mut drv = VirtioFsDriver::new(dev_id, registers, irq)?; - drv.init_dev().map_err(VirtioError::FsDriver)?; + let mut drv = VirtioFsDriver::new(dev_id, registers)?; + drv.init_dev(handlers, Some(irq)) + .map_err(VirtioError::FsDriver)?; drv.com_cfg.print_information(); Ok(drv) } diff --git a/src/drivers/fs/mod.rs b/src/drivers/fs/mod.rs index cebad3e144..3b9e305f25 100644 --- a/src/drivers/fs/mod.rs +++ b/src/drivers/fs/mod.rs @@ -21,7 +21,9 @@ use alloc::vec::Vec; use core::mem::MaybeUninit; use core::{mem, str}; +use ahash::RandomState; use fuse_abi::linux::fuse_out_header; +use hashbrown::HashMap; use num_enum::TryFromPrimitive; use pci_types::InterruptLine; use smallvec::SmallVec; @@ -30,7 +32,10 @@ use volatile::VolatileRef; use volatile::access::ReadOnly; use crate::config::VIRTIO_MAX_QUEUE_SIZE; -use crate::drivers::Driver; +#[cfg(not(feature = "pci"))] +use crate::drivers::mmio::get_filesystem_driver; +#[cfg(feature = "pci")] +use crate::drivers::pci::get_filesystem_driver; use crate::drivers::virtio::ControlRegisters; use crate::drivers::virtio::error::VirtioFsInitError; #[cfg(not(feature = "pci"))] @@ -42,6 +47,7 @@ use crate::drivers::virtio::virtqueue::split::SplitVq; use crate::drivers::virtio::virtqueue::{ AvailBufferToken, BufferElem, BufferType, VirtQueue, Virtq, }; +use crate::drivers::{Driver, InterruptHandlerQueue}; use crate::errno::Errno; use crate::fs::virtio_fs::{self, Rsp, RspHeader, VirtioFsError, VirtioFsInterface}; use crate::mm::device_alloc::DeviceAlloc; @@ -66,7 +72,6 @@ pub(crate) struct VirtioFsDriver { pub(super) isr_stat: IsrStatus, pub(super) notif_cfg: NotifCfg, pub(super) vqueues: Vec, - pub(super) irq: InterruptLine, } // Backend-independent interface for Virtio network driver @@ -86,7 +91,11 @@ impl VirtioFsDriver { /// /// See Virtio specification v1.1. - 3.1.1. /// and v1.1. - 5.11.5 - pub(crate) fn init_dev(&mut self) -> Result<(), VirtioFsInitError> { + pub(crate) fn init_dev( + &mut self, + handlers: &mut HashMap, + irq: Option, + ) -> Result<(), VirtioFsInitError> { // Reset self.com_cfg.reset_dev(); @@ -152,6 +161,12 @@ impl VirtioFsDriver { self.vqueues.push(vq); } + handlers.entry(irq.unwrap()).or_default().push_back(|| { + if let Some(driver) = get_filesystem_driver() { + driver.lock().handle_interrupt(); + }; + }); + // At this point the device is "live" self.com_cfg.drv_ok(); @@ -263,10 +278,6 @@ impl VirtioFsInterface for VirtioFsDriver { } impl Driver for VirtioFsDriver { - fn get_interrupt_number(&self) -> InterruptLine { - self.irq - } - fn get_name(&self) -> &'static str { "virtio" } diff --git a/src/drivers/fs/pci.rs b/src/drivers/fs/pci.rs index 63843609c2..7c75aae329 100644 --- a/src/drivers/fs/pci.rs +++ b/src/drivers/fs/pci.rs @@ -1,5 +1,7 @@ use alloc::vec::Vec; +use ahash::RandomState; +use hashbrown::HashMap; use volatile::VolatileRef; use crate::arch::pci::PciConfigRegion; @@ -8,6 +10,7 @@ use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; use crate::drivers::virtio::transport::pci; use crate::drivers::virtio::transport::pci::{PciCap, UniCapsColl}; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; impl VirtioFsDriver { fn map_cfg(cap: &PciCap) -> Option { @@ -49,12 +52,14 @@ impl VirtioFsDriver { isr_stat: isr_cfg, notif_cfg, vqueues: Vec::new(), - irq: device.get_irq().unwrap(), }) } /// Initializes virtio filesystem device - pub fn init(device: &PciDevice) -> Result { + pub fn init( + device: &PciDevice, + handlers: &mut HashMap, + ) -> Result { let mut drv = match pci::map_caps(device) { Ok(caps) => match VirtioFsDriver::new(caps, device) { Ok(driver) => driver, @@ -69,7 +74,7 @@ impl VirtioFsDriver { } }; - match drv.init_dev() { + match drv.init_dev(handlers, device.get_irq()) { Ok(()) => info!( "Filesystem device with id {:x}, has been initialized by driver!", drv.get_dev_id() diff --git a/src/drivers/mmio.rs b/src/drivers/mmio.rs index 24cee0c67a..fca912fb82 100644 --- a/src/drivers/mmio.rs +++ b/src/drivers/mmio.rs @@ -1,95 +1,6 @@ -use ahash::RandomState; -use hashbrown::HashMap; - #[cfg(feature = "virtio-console")] pub(crate) use crate::arch::kernel::mmio::get_console_driver; #[cfg(feature = "virtio-fs")] pub(crate) use crate::arch::kernel::mmio::get_filesystem_driver; #[cfg(feature = "virtio-vsock")] pub(crate) use crate::arch::kernel::mmio::get_vsock_driver; -#[cfg(any( - feature = "virtio-console", - all(target_arch = "riscv64", feature = "gem-net", not(feature = "pci")), - feature = "virtio-net", - feature = "virtio-fs", - feature = "virtio-vsock", -))] -use crate::drivers::Driver; -use crate::drivers::{InterruptHandlerQueue, InterruptLine}; -#[cfg(any( - all(target_arch = "riscv64", feature = "gem-net", not(feature = "pci")), - feature = "virtio-net", -))] -use crate::executor::device::NETWORK_DEVICE; - -pub(crate) fn get_interrupt_handlers() -> HashMap -{ - #[allow(unused_mut)] - let mut handlers: HashMap = - HashMap::with_hasher(RandomState::with_seeds(0, 0, 0, 0)); - - #[cfg(any( - all(target_arch = "riscv64", feature = "gem-net", not(feature = "pci")), - feature = "virtio-net", - ))] - if let Some(device) = NETWORK_DEVICE.lock().as_ref() { - handlers - .entry(device.get_interrupt_number()) - .or_default() - .push_back(crate::executor::network::network_handler); - } - - #[cfg(feature = "virtio-console")] - if let Some(drv) = get_console_driver() { - fn console_handler() { - let Some(driver) = get_console_driver() else { - return; - }; - - driver.lock().handle_interrupt(); - } - - let irq_number = drv.lock().get_interrupt_number(); - handlers - .entry(irq_number) - .or_default() - .push_back(console_handler); - } - - #[cfg(feature = "virtio-fs")] - if let Some(drv) = get_filesystem_driver() { - fn virtio_fs_handler() { - let Some(driver) = get_filesystem_driver() else { - return; - }; - - driver.lock().handle_interrupt(); - } - - let irq_number = drv.lock().get_interrupt_number(); - - handlers - .entry(irq_number) - .or_default() - .push_back(virtio_fs_handler); - } - - #[cfg(feature = "virtio-vsock")] - if let Some(drv) = get_vsock_driver() { - fn vsock_handler() { - let Some(driver) = get_vsock_driver() else { - return; - }; - - driver.lock().handle_interrupt(); - } - - let irq_number = drv.lock().get_interrupt_number(); - handlers - .entry(irq_number) - .or_default() - .push_back(vsock_handler); - } - - handlers -} diff --git a/src/drivers/mod.rs b/src/drivers/mod.rs index 90e925faae..1ea0f51c3a 100644 --- a/src/drivers/mod.rs +++ b/src/drivers/mod.rs @@ -17,6 +17,8 @@ pub mod vsock; use alloc::collections::VecDeque; +use ahash::RandomState; +use hashbrown::HashMap; #[cfg(feature = "pci")] pub(crate) use pci_types::InterruptLine; #[cfg(not(feature = "pci"))] @@ -66,24 +68,31 @@ pub mod error { /// A trait to determine general driver information #[allow(dead_code)] pub(crate) trait Driver { - /// Returns the interrupt number of the device - fn get_interrupt_number(&self) -> InterruptLine; - /// Returns the device driver name fn get_name(&self) -> &'static str; } pub(crate) fn init() { + #[cfg_attr( + all( + not(feature = "pci"), + not(target_arch = "riscv64"), + not(feature = "virtio") + ), + expect(unused_mut) + )] + let mut handlers = HashMap::with_hasher(RandomState::with_seeds(0, 0, 0, 0)); + // Initialize PCI Drivers #[cfg(feature = "pci")] - pci::init(); + pci::init(&mut handlers); #[cfg(all(not(feature = "pci"), feature = "virtio", target_arch = "x86_64"))] - crate::arch::x86_64::kernel::mmio::init_drivers(); + crate::arch::x86_64::kernel::mmio::init_drivers(&mut handlers); #[cfg(all(not(feature = "pci"), feature = "virtio", target_arch = "aarch64"))] - crate::arch::aarch64::kernel::mmio::init_drivers(); + crate::arch::aarch64::kernel::mmio::init_drivers(&mut handlers); #[cfg(target_arch = "riscv64")] - crate::arch::riscv64::kernel::init_drivers(); + crate::arch::riscv64::kernel::init_drivers(&mut handlers); - crate::arch::interrupts::install_handlers(); + crate::arch::interrupts::install_handlers(handlers); } diff --git a/src/drivers/net/gem.rs b/src/drivers/net/gem.rs index a1ae9ae3af..0ecbb4ccdd 100644 --- a/src/drivers/net/gem.rs +++ b/src/drivers/net/gem.rs @@ -9,6 +9,8 @@ use core::alloc::Layout; use core::ptr::NonNull; use core::{ptr, slice}; +use ahash::RandomState; +use hashbrown::HashMap; use memory_addresses::VirtAddr; use smoltcp::phy::{ChecksumCapabilities, DeviceCapabilities}; use thiserror::Error; @@ -18,7 +20,7 @@ use tock_registers::{register_bitfields, register_structs}; use crate::drivers::error::DriverError; use crate::drivers::net::{NetworkDriver, mtu}; -use crate::drivers::{Driver, InterruptLine}; +use crate::drivers::{Driver, InterruptHandlerQueue, InterruptLine}; use crate::executor::network::wake_network_waker; use crate::mm::device_alloc::DeviceAlloc; @@ -207,7 +209,6 @@ pub enum GEMError { /// the device itself. pub struct GEMDriver { mtu: u16, - irq: u8, mac: [u8; 6], rx_counter: u32, rx_fields: RxFields, @@ -316,10 +317,6 @@ impl TxFields { } impl Driver for GEMDriver { - fn get_interrupt_number(&self) -> InterruptLine { - self.irq - } - fn get_name(&self) -> &'static str { "gem" } @@ -574,6 +571,7 @@ pub fn init_device( irq: u8, phy_addr: u32, mac: [u8; 6], + handlers: &mut HashMap, ) -> Result { debug!("Init GEM at {gem_base:p}"); @@ -806,9 +804,13 @@ pub fn init_device( mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); + handlers + .entry(irq) + .or_default() + .push_back(crate::executor::network::network_handler); + Ok(GEMDriver { mtu: mtu(), - irq, mac, rx_counter: 0, rx_fields: RxFields { diff --git a/src/drivers/net/loopback.rs b/src/drivers/net/loopback.rs index 85d814c13a..3dd794add4 100644 --- a/src/drivers/net/loopback.rs +++ b/src/drivers/net/loopback.rs @@ -6,8 +6,8 @@ use hermit_sync::SpinMutex; use smoltcp::phy; use smoltcp::time::Instant; +use crate::drivers::Driver; use crate::drivers::net::NetworkDriver; -use crate::drivers::{Driver, InterruptLine}; use crate::executor::network::wake_network_waker; use crate::mm::device_alloc::DeviceAlloc; @@ -26,12 +26,6 @@ impl LoopbackDriver { } impl Driver for LoopbackDriver { - fn get_interrupt_number(&self) -> InterruptLine { - // This is called by mmio / pci specific code, this driver - // is using neither. - unimplemented!() - } - fn get_name(&self) -> &'static str { "loopback" } diff --git a/src/drivers/net/rtl8139.rs b/src/drivers/net/rtl8139.rs index f5976d8991..c4b0db6d7f 100644 --- a/src/drivers/net/rtl8139.rs +++ b/src/drivers/net/rtl8139.rs @@ -8,7 +8,9 @@ use core::hint::spin_loop; use core::mem::ManuallyDrop; use core::ptr::NonNull; +use ahash::RandomState; use endian_num::{le16, le32, le64}; +use hashbrown::HashMap; use pci_types::{Bar, CommandRegister, InterruptLine, MAX_BARS}; use smoltcp::phy::DeviceCapabilities; use thiserror::Error; @@ -17,10 +19,10 @@ use volatile::{VolatileFieldAccess, VolatilePtr, VolatileRef, map_field}; use crate::arch::kernel::interrupts::*; use crate::arch::pci::PciConfigRegion; -use crate::drivers::Driver; use crate::drivers::error::DriverError; use crate::drivers::net::{NetworkDriver, mtu}; use crate::drivers::pci::PciDevice; +use crate::drivers::{Driver, InterruptHandlerQueue}; use crate::executor::network::wake_network_waker; use crate::mm::device_alloc::DeviceAlloc; @@ -480,7 +482,6 @@ struct TxFields { pub(crate) struct RTL8139Driver { regs: VolatileRef<'static, Regs>, mtu: u16, - irq: InterruptLine, mac: [u8; 6], rx_fields: RxFields, tx_fields: TxFields, @@ -698,10 +699,6 @@ impl NetworkDriver for RTL8139Driver { } impl Driver for RTL8139Driver { - fn get_interrupt_number(&self) -> InterruptLine { - self.irq - } - fn get_name(&self) -> &'static str { "rtl8139" } @@ -748,6 +745,7 @@ impl Drop for RTL8139Driver { pub(crate) fn init_device( device: &PciDevice, + handlers: &mut HashMap, ) -> Result { let irq = device.get_irq().unwrap(); let mut regs = None; @@ -889,12 +887,15 @@ pub(crate) fn init_device( ); info!("RTL8139 use interrupt line {irq}"); + handlers + .entry(irq) + .or_default() + .push_back(crate::executor::network::network_handler); add_irq_name(irq, "rtl8139"); Ok(RTL8139Driver { regs, mtu: mtu(), - irq, mac, rx_fields: RxFields { rxbuffer, diff --git a/src/drivers/net/virtio/mmio.rs b/src/drivers/net/virtio/mmio.rs index ea21245e3c..d2eb68ccd6 100644 --- a/src/drivers/net/virtio/mmio.rs +++ b/src/drivers/net/virtio/mmio.rs @@ -1,18 +1,19 @@ +use ahash::RandomState; +use hashbrown::HashMap; use smoltcp::phy::ChecksumCapabilities; use virtio::mmio::{DeviceRegisters, DeviceRegistersVolatileFieldAccess}; use volatile::VolatileRef; -use crate::drivers::InterruptLine; use crate::drivers::net::virtio::{Init, NetDevCfg, Uninit, VirtioNetDriver}; use crate::drivers::virtio::error::VirtioError; use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; // Backend-dependent interface for Virtio network driver impl VirtioNetDriver { pub fn new( dev_id: u16, mut registers: VolatileRef<'static, DeviceRegisters>, - irq: InterruptLine, ) -> Result { let dev_cfg_raw: &'static virtio::net::Config = unsafe { &*registers @@ -39,7 +40,6 @@ impl VirtioNetDriver { notif_cfg, inner: Uninit, num_vqs: 0, - irq, checksums: ChecksumCapabilities::default(), }) } @@ -53,9 +53,12 @@ impl VirtioNetDriver { dev_id: u16, registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, + handlers: &mut HashMap, ) -> Result, VirtioError> { - let drv = VirtioNetDriver::new(dev_id, registers, irq)?; - let mut drv = drv.init_dev().map_err(VirtioError::NetDriver)?; + let drv = VirtioNetDriver::new(dev_id, registers)?; + let mut drv = drv + .init_dev(handlers, Some(irq)) + .map_err(VirtioError::NetDriver)?; drv.print_information(); Ok(drv) } diff --git a/src/drivers/net/virtio/mod.rs b/src/drivers/net/virtio/mod.rs index 03fc66b399..f7b71bdba2 100644 --- a/src/drivers/net/virtio/mod.rs +++ b/src/drivers/net/virtio/mod.rs @@ -20,6 +20,8 @@ use core::mem::{ManuallyDrop, MaybeUninit}; use core::str::FromStr; use core::{mem, slice}; +use ahash::RandomState; +use hashbrown::HashMap; use smallvec::SmallVec; use smoltcp::phy::{Checksum, ChecksumCapabilities, DeviceCapabilities}; use smoltcp::wire::{ @@ -46,7 +48,7 @@ use crate::drivers::virtio::virtqueue::split::SplitVq; use crate::drivers::virtio::virtqueue::{ AvailBufferToken, BufferElem, BufferType, UsedBufferToken, VirtQueue, Virtq, }; -use crate::drivers::{Driver, InterruptLine}; +use crate::drivers::{Driver, InterruptHandlerQueue, InterruptLine}; use crate::executor::network::wake_network_waker; use crate::mm::device_alloc::DeviceAlloc; @@ -248,7 +250,6 @@ pub(crate) struct VirtioNetDriver { pub(super) inner: T, pub(super) num_vqs: u16, - pub(super) irq: InterruptLine, /// Describes for what protocols and in which directions, if any, the checksum /// should be calculated in software. It is the complement of what is offloaded /// to the hardware. @@ -598,10 +599,6 @@ impl smoltcp::phy::Device for VirtioNetDriver { } impl Driver for VirtioNetDriver { - fn get_interrupt_number(&self) -> InterruptLine { - self.irq - } - fn get_name(&self) -> &'static str { "virtio" } @@ -757,7 +754,11 @@ impl VirtioNetDriver { /// /// See Virtio specification v1.1. - 3.1.1. /// and v1.1. - 5.1.5 - pub fn init_dev(mut self) -> Result, VirtioNetError> { + pub fn init_dev( + mut self, + handlers: &mut HashMap, + irq: Option, + ) -> Result, VirtioNetError> { // Reset self.com_cfg.reset_dev(); @@ -840,6 +841,11 @@ impl VirtioNetDriver { self.dev_cfg.dev_id ); + handlers + .entry(irq.unwrap()) + .or_default() + .push_back(crate::executor::network::network_handler); + // At this point the device is "live" self.com_cfg.drv_ok(); @@ -864,7 +870,6 @@ impl VirtioNetDriver { notif_cfg: self.notif_cfg, inner, num_vqs: self.num_vqs, - irq: self.irq, checksums: self.checksums, }) } diff --git a/src/drivers/net/virtio/pci.rs b/src/drivers/net/virtio/pci.rs index 104ab84060..e9482da198 100644 --- a/src/drivers/net/virtio/pci.rs +++ b/src/drivers/net/virtio/pci.rs @@ -1,3 +1,5 @@ +use ahash::RandomState; +use hashbrown::HashMap; use pci_types::CommandRegister; use smoltcp::phy::ChecksumCapabilities; use volatile::VolatileRef; @@ -9,6 +11,7 @@ use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; use crate::drivers::virtio::transport::pci; use crate::drivers::virtio::transport::pci::{PciCap, UniCapsColl}; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; // Backend-dependent interface for Virtio network driver impl VirtioNetDriver { @@ -51,7 +54,6 @@ impl VirtioNetDriver { notif_cfg, inner: Uninit, num_vqs: 0, - irq: device.get_irq().unwrap(), checksums: ChecksumCapabilities::default(), }) } @@ -66,6 +68,7 @@ impl VirtioNetDriver { /// [VirtioNetDriver](structs.virtionetdriver.html) or an [VirtioError](enums.virtioerror.html). pub(crate) fn init( device: &PciDevice, + handlers: &mut HashMap, ) -> Result, VirtioError> { // enable bus master mode device.set_command(CommandRegister::BUS_MASTER_ENABLE); @@ -84,7 +87,7 @@ impl VirtioNetDriver { } }; - let initialized_drv = match drv.init_dev() { + let initialized_drv = match drv.init_dev(handlers, device.get_irq()) { Ok(initialized_drv) => { info!( "Network device with id {:x}, has been initialized by driver!", diff --git a/src/drivers/pci.rs b/src/drivers/pci.rs index 8b4cd34621..9ade75fa80 100644 --- a/src/drivers/pci.rs +++ b/src/drivers/pci.rs @@ -365,90 +365,12 @@ impl PciDriver { _ => None, } } - - fn get_interrupt_handler(&self) -> (InterruptLine, fn()) { - #[allow(unreachable_patterns)] - match self { - #[cfg(feature = "virtio-vsock")] - Self::VirtioVsock(drv) => { - fn vsock_handler() { - let Some(driver) = get_vsock_driver() else { - return; - }; - - driver.lock().handle_interrupt(); - } - - let irq_number = drv.lock().get_interrupt_number(); - - (irq_number, vsock_handler) - } - #[cfg(feature = "virtio-fs")] - Self::VirtioFs(drv) => { - fn virtio_fs_handler() { - let Some(driver) = get_filesystem_driver() else { - return; - }; - - driver.lock().handle_interrupt(); - } - - let irq_number = drv.lock().get_interrupt_number(); - - (irq_number, virtio_fs_handler) - } - #[cfg(feature = "virtio-console")] - Self::VirtioConsole(drv) => { - fn console_handler() { - let Some(driver) = get_console_driver() else { - return; - }; - - driver.lock().handle_interrupt(); - } - - let irq_number = drv.lock().get_interrupt_number(); - (irq_number, console_handler) - } - _ => todo!(), - } - } } pub(crate) fn register_driver(drv: PciDriver) { PCI_DRIVERS.with(|pci_drivers| pci_drivers.unwrap().push(drv)); } -pub(crate) fn get_interrupt_handlers() -> HashMap -{ - let mut handlers: HashMap = - HashMap::with_hasher(RandomState::with_seeds(0, 0, 0, 0)); - - for drv in PCI_DRIVERS.finalize().iter() { - let (irq_number, handler) = drv.get_interrupt_handler(); - - handlers.entry(irq_number).or_default().push_back(handler); - } - - #[cfg(target_arch = "x86_64")] - { - use crate::kernel::serial::get_serial_handler; - let (irq_number, handler) = get_serial_handler(); - - handlers.entry(irq_number).or_default().push_back(handler); - } - - #[cfg(any(feature = "rtl8139", feature = "virtio-net"))] - if let Some(device) = NETWORK_DEVICE.lock().as_ref() { - handlers - .entry(device.get_interrupt_number()) - .or_default() - .push_back(crate::executor::network::network_handler); - } - - handlers -} - #[cfg(all(not(feature = "rtl8139"), feature = "virtio-net"))] pub(crate) type NetworkDevice = VirtioNetDriver; @@ -479,7 +401,13 @@ pub(crate) fn get_filesystem_driver() -> Option<&'static InterruptTicketMutex, +) { // virtio: 4.1.2 PCI Device Discovery without_interrupts(|| { for adapter in PCI_DEVICES.finalize().iter().filter(|x| { @@ -495,7 +423,7 @@ pub(crate) fn init() { error!("Virtio support is disabled."); #[cfg(feature = "virtio")] - match pci_virtio::init_device(adapter) { + match pci_virtio::init_device(adapter, handlers) { #[cfg(feature = "virtio-console")] Ok(VirtioDriver::Console(drv)) => { register_driver(PciDriver::VirtioConsole(InterruptTicketMutex::new(*drv))); @@ -529,7 +457,7 @@ pub(crate) fn init() { adapter.device_id() ); - match rtl8139::init_device(adapter) { + match rtl8139::init_device(adapter, handlers) { Ok(drv) => *NETWORK_DEVICE.lock() = Some(drv), Err(err) => error!("Could not initialize rtl8139 device: {err}"), } diff --git a/src/drivers/virtio/transport/mmio.rs b/src/drivers/virtio/transport/mmio.rs index 27f2147da4..231be90ebe 100644 --- a/src/drivers/virtio/transport/mmio.rs +++ b/src/drivers/virtio/transport/mmio.rs @@ -4,9 +4,10 @@ //! For details on the Rust definitions, see [`virtio::mmio`]. //! //! [Virtio Over MMIO]: https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-1650002 - use core::mem; +use ahash::RandomState; +use hashbrown::HashMap; use memory_addresses::PhysAddr; use virtio::mmio::{ DeviceRegisters, DeviceRegistersVolatileFieldAccess, DeviceRegistersVolatileWideFieldAccess, @@ -16,7 +17,6 @@ use virtio::{DeviceStatus, le32}; use volatile::access::ReadOnly; use volatile::{VolatilePtr, VolatileRef}; -use crate::drivers::InterruptLine; #[cfg(feature = "virtio-console")] use crate::drivers::console::VirtioConsoleDriver; use crate::drivers::error::DriverError; @@ -28,6 +28,7 @@ use crate::drivers::virtio::error::VirtioError; use crate::drivers::virtio::{ControlRegisters, VirtioIdExt}; #[cfg(feature = "virtio-vsock")] use crate::drivers::vsock::VirtioVsockDriver; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; pub struct VqCfgHandler<'a> { vq_index: u16, @@ -327,6 +328,7 @@ pub(crate) enum VirtioDriver { pub(crate) fn init_device( registers: VolatileRef<'static, DeviceRegisters>, irq_no: InterruptLine, + handlers: &mut HashMap, ) -> Result { let dev_id: u16 = 0; @@ -340,7 +342,7 @@ pub(crate) fn init_device( // Verify the device-ID to find the network card match registers.as_ptr().device_id().read() { #[cfg(feature = "virtio-console")] - virtio::Id::Console => match VirtioConsoleDriver::init(dev_id, registers, irq_no) { + virtio::Id::Console => match VirtioConsoleDriver::init(dev_id, registers, irq_no, handlers) { Ok(virt_console_drv) => { info!("Virtio console driver initialized."); @@ -360,7 +362,7 @@ pub(crate) fn init_device( virtio::Id::Fs => { // TODO: check subclass // TODO: proper error handling on driver creation fail - match VirtioFsDriver::init(dev_id, registers, irq_no) { + match VirtioFsDriver::init(dev_id, registers, irq_no, handlers) { Ok(virt_fs_drv) => { info!("Virtio filesystem driver initialized."); crate::arch::interrupts::add_irq_name(irq_no, "virtio"); @@ -373,7 +375,7 @@ pub(crate) fn init_device( } } #[cfg(feature = "virtio-net")] - virtio::Id::Net => match VirtioNetDriver::init(dev_id, registers, irq_no) { + virtio::Id::Net => match VirtioNetDriver::init(dev_id, registers, irq_no, handlers) { Ok(virt_net_drv) => { info!("Virtio network driver initialized."); @@ -388,7 +390,7 @@ pub(crate) fn init_device( } }, #[cfg(feature = "virtio-vsock")] - virtio::Id::Vsock => match VirtioVsockDriver::init(dev_id, registers, irq_no) { + virtio::Id::Vsock => match VirtioVsockDriver::init(dev_id, registers, irq_no, handlers) { Ok(virt_vsock_drv) => { info!("Virtio sock driver initialized."); diff --git a/src/drivers/virtio/transport/pci.rs b/src/drivers/virtio/transport/pci.rs index babe017063..66f0592092 100644 --- a/src/drivers/virtio/transport/pci.rs +++ b/src/drivers/virtio/transport/pci.rs @@ -8,6 +8,8 @@ use alloc::vec::Vec; use core::ptr::{self, NonNull}; +use ahash::RandomState; +use hashbrown::HashMap; use memory_addresses::PhysAddr; use pci_types::capability::PciCapability; use virtio::pci::{ @@ -37,6 +39,7 @@ use crate::drivers::virtio::transport::pci::PciBar as VirtioPciBar; use crate::drivers::virtio::{ControlRegisters, VirtioIdExt}; #[cfg(feature = "virtio-vsock")] use crate::drivers::vsock::VirtioVsockDriver; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; /// Maps a given device specific pci configuration structure and /// returns a static reference to it. @@ -624,6 +627,11 @@ pub(crate) fn map_caps(device: &PciDevice) -> Result, + #[allow(unused_variables)] handlers: &mut HashMap< + InterruptLine, + InterruptHandlerQueue, + RandomState, + >, ) -> Result { let device_id = device.device_id(); @@ -642,7 +650,7 @@ pub(crate) fn init_device( match id { #[cfg(feature = "virtio-console")] - virtio::Id::Console => match VirtioConsoleDriver::init(device) { + virtio::Id::Console => match VirtioConsoleDriver::init(device, handlers) { Ok(virt_console_drv) => { info!("Virtio console driver initialized."); @@ -663,7 +671,7 @@ pub(crate) fn init_device( virtio::Id::Fs => { // TODO: check subclass // TODO: proper error handling on driver creation fail - match VirtioFsDriver::init(device) { + match VirtioFsDriver::init(device, handlers) { Ok(virt_fs_drv) => { info!("Virtio filesystem driver initialized."); let irq = device.get_irq().unwrap(); @@ -683,7 +691,7 @@ pub(crate) fn init_device( not(feature = "rtl8139"), feature = "virtio-net", ))] - virtio::Id::Net => match VirtioNetDriver::init(device) { + virtio::Id::Net => match VirtioNetDriver::init(device, handlers) { Ok(virt_net_drv) => { info!("Virtio network driver initialized."); @@ -701,7 +709,7 @@ pub(crate) fn init_device( } }, #[cfg(feature = "virtio-vsock")] - virtio::Id::Vsock => match VirtioVsockDriver::init(device) { + virtio::Id::Vsock => match VirtioVsockDriver::init(device, handlers) { Ok(virt_sock_drv) => { info!("Virtio sock driver initialized."); diff --git a/src/drivers/vsock/mmio.rs b/src/drivers/vsock/mmio.rs index 071d1735c7..34c6af4075 100644 --- a/src/drivers/vsock/mmio.rs +++ b/src/drivers/vsock/mmio.rs @@ -1,18 +1,19 @@ -use virtio::vsock::Config; +use ahash::RandomState; +use hashbrown::HashMap; use virtio::mmio::{DeviceRegisters, DeviceRegistersVolatileFieldAccess}; +use virtio::vsock::Config; use volatile::VolatileRef; -use crate::drivers::InterruptLine; -use crate::drivers::vsock::{EventQueue, RxQueue, TxQueue, VirtioVsockDriver, VsockDevCfg}; use crate::drivers::virtio::error::VirtioError; use crate::drivers::virtio::transport::mmio::{ComCfg, IsrStatus, NotifCfg}; +use crate::drivers::vsock::{EventQueue, RxQueue, TxQueue, VirtioVsockDriver, VsockDevCfg}; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; // Backend-dependent interface for Virtio vsock driver impl VirtioVsockDriver { pub fn new( dev_id: u16, mut registers: VolatileRef<'static, DeviceRegisters>, - irq: InterruptLine, ) -> Result { let dev_cfg_raw: &'static Config = unsafe { &*registers @@ -37,7 +38,6 @@ impl VirtioVsockDriver { com_cfg: ComCfg::new(registers), isr_stat, notif_cfg, - irq, event_vq: EventQueue::new(), recv_vq: RxQueue::new(), send_vq: TxQueue::new(), @@ -53,9 +53,11 @@ impl VirtioVsockDriver { dev_id: u16, registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, + handlers: &mut HashMap, ) -> Result { - let mut drv = VirtioVsockDriver::new(dev_id, registers, irq)?; - drv.init_dev().map_err(VirtioError::VsockDriver)?; + let mut drv = VirtioVsockDriver::new(dev_id, registers)?; + drv.init_dev(handlers, Some(irq)) + .map_err(VirtioError::VsockDriver)?; drv.com_cfg.print_information(); Ok(drv) } diff --git a/src/drivers/vsock/mod.rs b/src/drivers/vsock/mod.rs index 77588be9d1..c0fa5e79f4 100644 --- a/src/drivers/vsock/mod.rs +++ b/src/drivers/vsock/mod.rs @@ -12,6 +12,8 @@ cfg_select! { use alloc::boxed::Box; use alloc::vec::Vec; +use ahash::RandomState; +use hashbrown::HashMap; use pci_types::InterruptLine; use smallvec::SmallVec; use virtio::vsock::{ConfigVolatileFieldAccess, Hdr}; @@ -20,7 +22,10 @@ use volatile::access::ReadOnly; use super::virtio::virtqueue::VirtQueue; use crate::config::VIRTIO_MAX_QUEUE_SIZE; -use crate::drivers::Driver; +#[cfg(not(feature = "pci"))] +use crate::drivers::mmio::get_vsock_driver; +#[cfg(feature = "pci")] +use crate::drivers::pci::get_vsock_driver; use crate::drivers::virtio::ControlRegisters; use crate::drivers::virtio::error::VirtioVsockError; #[cfg(not(feature = "pci"))] @@ -31,6 +36,7 @@ use crate::drivers::virtio::virtqueue::split::SplitVq; use crate::drivers::virtio::virtqueue::{ AvailBufferToken, BufferElem, BufferType, UsedBufferToken, Virtq, }; +use crate::drivers::{Driver, InterruptHandlerQueue}; use crate::mm::device_alloc::DeviceAlloc; fn fill_queue(vq: &mut VirtQueue, num_packets: u16, packet_size: u32) { @@ -260,7 +266,6 @@ pub(crate) struct VirtioVsockDriver { pub(super) com_cfg: ComCfg, pub(super) isr_stat: IsrStatus, pub(super) notif_cfg: NotifCfg, - pub(super) irq: InterruptLine, pub(super) event_vq: EventQueue, pub(super) recv_vq: RxQueue, @@ -268,10 +273,6 @@ pub(crate) struct VirtioVsockDriver { } impl Driver for VirtioVsockDriver { - fn get_interrupt_number(&self) -> InterruptLine { - self.irq - } - fn get_name(&self) -> &'static str { "virtio" } @@ -326,7 +327,11 @@ impl VirtioVsockDriver { /// /// See Virtio specification v1.1. - 3.1.1. /// and v1.1. - 5.10.6 - pub fn init_dev(&mut self) -> Result<(), VirtioVsockError> { + pub fn init_dev( + &mut self, + handlers: &mut HashMap, + irq: Option, + ) -> Result<(), VirtioVsockError> { // Reset self.com_cfg.reset_dev(); @@ -402,6 +407,13 @@ impl VirtioVsockDriver { ) .unwrap(), )); + + handlers.entry(irq.unwrap()).or_default().push_back(|| { + if let Some(driver) = get_vsock_driver() { + driver.lock().handle_interrupt(); + }; + }); + // Interrupt for event packets is wanted self.event_vq.enable_notifs(); diff --git a/src/drivers/vsock/pci.rs b/src/drivers/vsock/pci.rs index 6b3c64c9ed..c590cf1791 100644 --- a/src/drivers/vsock/pci.rs +++ b/src/drivers/vsock/pci.rs @@ -1,3 +1,5 @@ +use ahash::RandomState; +use hashbrown::HashMap; use volatile::VolatileRef; use crate::arch::pci::PciConfigRegion; @@ -6,6 +8,7 @@ use crate::drivers::virtio::error::{self, VirtioError}; use crate::drivers::virtio::transport::pci; use crate::drivers::virtio::transport::pci::{PciCap, UniCapsColl}; use crate::drivers::vsock::{EventQueue, RxQueue, TxQueue, VirtioVsockDriver, VsockDevCfg}; +use crate::drivers::{InterruptHandlerQueue, InterruptLine}; impl VirtioVsockDriver { fn map_cfg(cap: &PciCap) -> Option { @@ -46,7 +49,6 @@ impl VirtioVsockDriver { com_cfg, isr_stat: isr_cfg, notif_cfg, - irq: device.get_irq().unwrap(), event_vq: EventQueue::new(), recv_vq: RxQueue::new(), send_vq: TxQueue::new(), @@ -58,6 +60,7 @@ impl VirtioVsockDriver { /// Returns a driver instance of VirtioVsockDriver. pub(crate) fn init( device: &PciDevice, + handlers: &mut HashMap, ) -> Result { let mut drv = match pci::map_caps(device) { Ok(caps) => match VirtioVsockDriver::new(caps, device) { @@ -73,7 +76,7 @@ impl VirtioVsockDriver { } }; - match drv.init_dev() { + match drv.init_dev(handlers, device.get_irq()) { Ok(()) => { let cid = drv.get_cid(); info!("Socket device with cid {cid:x}, has been initialized by driver!");