From 4e80af2b029f87f36e282a7655c0ba81438544ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=87a=C4=9Fatay=20Yi=C4=9Fit=20=C5=9Eahin?= Date: Tue, 9 Jun 2026 15:02:50 +0200 Subject: [PATCH] refactor(interrupts): construct handler mappings during device init MSI-X will require support for more than one interrupt vector per driver and more information from the driver side to decide how to handle the interrupts correctly. Revise how the mappings are constructed to make the construction more flexible and prepare for that use case. --- src/arch/aarch64/kernel/interrupts.rs | 11 ++-- src/arch/aarch64/kernel/mmio.rs | 44 ++++++++----- src/arch/riscv64/kernel/devicetree.rs | 10 ++- src/arch/riscv64/kernel/interrupts.rs | 12 ++-- src/arch/x86_64/kernel/interrupts.rs | 26 +++++--- src/arch/x86_64/kernel/mmio.rs | 19 ++++-- src/arch/x86_64/kernel/serial.rs | 28 +++------ src/drivers/console/mmio.rs | 12 ++-- src/drivers/console/mod.rs | 21 ++++--- src/drivers/console/pci.rs | 9 ++- src/drivers/fs/mmio.rs | 12 ++-- src/drivers/fs/mod.rs | 25 +++++--- src/drivers/fs/pci.rs | 11 +++- src/drivers/mmio.rs | 89 -------------------------- src/drivers/mod.rs | 25 +++++--- src/drivers/net/gem.rs | 16 ++--- src/drivers/net/loopback.rs | 8 +-- src/drivers/net/rtl8139.rs | 15 ++--- src/drivers/net/virtio/mmio.rs | 13 ++-- src/drivers/net/virtio/mod.rs | 21 ++++--- src/drivers/net/virtio/pci.rs | 7 ++- src/drivers/pci.rs | 90 +++------------------------ src/drivers/virtio/transport/mmio.rs | 14 +++-- src/drivers/virtio/transport/pci.rs | 16 +++-- src/drivers/vsock/mmio.rs | 16 ++--- src/drivers/vsock/mod.rs | 26 +++++--- src/drivers/vsock/pci.rs | 7 ++- 27 files changed, 269 insertions(+), 334 deletions(-) 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!");