From b2838e57c3a440dd43a606f647a30645a10c9549 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 | 16 ++--- src/arch/aarch64/kernel/mmio.rs | 18 ++--- src/arch/riscv64/kernel/devicetree.rs | 10 ++- src/arch/riscv64/kernel/interrupts.rs | 13 +--- src/arch/x86_64/kernel/interrupts.rs | 12 ++-- src/arch/x86_64/kernel/mmio.rs | 15 +++-- src/arch/x86_64/kernel/serial.rs | 33 ++++----- src/drivers/console/mmio.rs | 10 +-- src/drivers/console/mod.rs | 19 ++++-- src/drivers/console/pci.rs | 5 +- src/drivers/fs/mmio.rs | 10 +-- src/drivers/fs/mod.rs | 23 +++++-- src/drivers/fs/pci.rs | 9 ++- src/drivers/mmio.rs | 89 ------------------------- src/drivers/mod.rs | 30 ++++++--- src/drivers/net/gem.rs | 14 ++-- src/drivers/net/loopback.rs | 8 +-- src/drivers/net/rtl8139.rs | 15 ++--- src/drivers/net/virtio/mmio.rs | 11 +-- src/drivers/net/virtio/mod.rs | 19 +++--- src/drivers/net/virtio/pci.rs | 5 +- src/drivers/pci.rs | 96 +++------------------------ src/drivers/virtio/transport/mmio.rs | 11 +-- src/drivers/virtio/transport/pci.rs | 23 +++++-- src/drivers/vsock/mmio.rs | 10 +-- src/drivers/vsock/mod.rs | 24 +++++-- src/drivers/vsock/pci.rs | 5 +- 27 files changed, 221 insertions(+), 332 deletions(-) diff --git a/src/arch/aarch64/kernel/interrupts.rs b/src/arch/aarch64/kernel/interrupts.rs index ede0f8d8be..b4527817e6 100644 --- a/src/arch/aarch64/kernel/interrupts.rs +++ b/src/arch/aarch64/kernel/interrupts.rs @@ -18,11 +18,7 @@ use crate::arch::aarch64::kernel::core_local::{core_id, core_scheduler, incremen use crate::arch::aarch64::kernel::scheduler::State; use crate::arch::aarch64::kernel::serial::handle_uart_interrupt; 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::drivers::InterruptHandlerMap; use crate::env; use crate::mm::{PageAlloc, PageRangeAllocator}; use crate::scheduler::{self, CoreId, timer_interrupts}; @@ -40,8 +36,7 @@ static mut TIMER_INTERRUPT: u32 = 0; /// Number of the UART interrupt static mut UART_INTERRUPT: u32 = 0; /// Possible interrupt handlers -static INTERRUPT_HANDLERS: OnceCell> = - OnceCell::new(); +static INTERRUPT_HANDLERS: OnceCell = OnceCell::new(); /// Driver for the Arm Generic Interrupt Controller version 3 (or 4). pub(crate) static GIC: SpinMutex>> = SpinMutex::new(None); @@ -87,16 +82,15 @@ pub fn disable() { dmb(ISH); } -pub(crate) fn install_handlers() { - let mut handlers: HashMap = +pub(crate) fn install_handlers(old_handlers: InterruptHandlerMap) { + let mut handlers: InterruptHandlerMap = 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 faa4900b04..4c6730ffe8 100644 --- a/src/arch/aarch64/kernel/mmio.rs +++ b/src/arch/aarch64/kernel/mmio.rs @@ -17,6 +17,7 @@ use crate::arch::aarch64::kernel::interrupts::GIC; use crate::arch::aarch64::mm::paging::{self, PageSize}; #[cfg(feature = "virtio-console")] use crate::console::IoDevice; +use crate::drivers::InterruptHandlerMap; #[cfg(feature = "virtio-console")] use crate::drivers::console::VirtioConsoleDriver; #[cfg(feature = "virtio-console")] @@ -117,7 +118,7 @@ pub(crate) fn get_vsock_driver() -> Option<&'static InterruptTicketMutex 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 { diff --git a/src/arch/riscv64/kernel/devicetree.rs b/src/arch/riscv64/kernel/devicetree.rs index c418b27e16..92e1697175 100644 --- a/src/arch/riscv64/kernel/devicetree.rs +++ b/src/arch/riscv64/kernel/devicetree.rs @@ -22,6 +22,7 @@ use crate::arch::riscv64::kernel::mmio::MmioDriver; use crate::arch::riscv64::mm::paging::{self, PageSize}; #[cfg(feature = "virtio-console")] use crate::console::IoDevice; +use crate::drivers::InterruptHandlerMap; #[cfg(feature = "virtio-console")] use crate::drivers::console::VirtioUART; #[cfg(all(feature = "virtio-console", not(feature = "pci")))] @@ -97,9 +98,13 @@ pub fn init() { info!("Model: {model}"); } +#[cfg_attr( + any(not(any(feature = "gem-net", feature = "virtio")), feature = "pci"), + expect(unused_variables) +)] /// Inits drivers based on the device tree /// This function should only be called once -pub fn init_drivers() { +pub fn init_drivers(handlers: &mut InterruptHandlerMap) { // 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..b346753ab9 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::InterruptHandlerMap; use crate::scheduler; /// Base address of the PLIC, only one access at the same time is allowed @@ -25,8 +21,7 @@ static PLIC_CONTEXT: SpinMutex = SpinMutex::new(0x0); /// PLIC context for new interrupt handlers static CURRENT_INTERRUPTS: SpinMutex> = SpinMutex::new(Vec::new()); -static INTERRUPT_HANDLERS: OnceCell> = - OnceCell::new(); +static INTERRUPT_HANDLERS: OnceCell = OnceCell::new(); /// Init Interrupts pub(crate) fn install() { @@ -119,9 +114,7 @@ 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: InterruptHandlerMap) { 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 fb07fb6d9b..3ed4572acb 100644 --- a/src/arch/x86_64/kernel/interrupts.rs +++ b/src/arch/x86_64/kernel/interrupts.rs @@ -16,14 +16,10 @@ 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::InterruptHandlerMap; use crate::scheduler::{self, CoreId}; -static IRQ_HANDLERS: OnceCell> = OnceCell::new(); +static IRQ_HANDLERS: OnceCell = OnceCell::new(); static IRQ_NAMES: InterruptTicketMutex> = InterruptTicketMutex::new(HashMap::with_hasher(RandomState::with_seeds(0, 0, 0, 0))); @@ -161,8 +157,8 @@ 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(handlers: InterruptHandlerMap) { + 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..50bc6871fb 100644 --- a/src/arch/x86_64/kernel/mmio.rs +++ b/src/arch/x86_64/kernel/mmio.rs @@ -20,6 +20,7 @@ use crate::arch::x86_64::mm::paging; use crate::arch::x86_64::mm::paging::{ BasePageSize, PageSize, PageTableEntryFlags, PageTableEntryFlagsExt, }; +use crate::drivers::InterruptHandlerMap; #[cfg(feature = "virtio-console")] use crate::drivers::console::VirtioConsoleDriver; #[cfg(feature = "virtio-fs")] @@ -217,8 +218,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 InterruptHandlerMap, +) { + 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 +244,7 @@ fn register_mmio(mmio: VolatileRef<'static, DeviceRegisters>, irq: u8) { } } -pub(crate) fn init_drivers() { +pub(crate) fn init_drivers(handlers: &mut InterruptHandlerMap) { without_interrupts(|| { let layout = PageLayout::from_size(BasePageSize::SIZE as usize).unwrap(); let page_range = PageBox::new(layout).unwrap(); @@ -249,11 +254,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..0e6eea22e4 100644 --- a/src/arch/x86_64/kernel/serial.rs +++ b/src/arch/x86_64/kernel/serial.rs @@ -6,9 +6,7 @@ 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::drivers::InterruptHandlerMap; use crate::errno::Errno; #[cfg(feature = "pci")] @@ -79,21 +77,24 @@ impl Write for SerialDevice { } #[cfg(feature = "pci")] -pub(crate) fn get_serial_handler() -> (InterruptLine, fn()) { - fn serial_handler() { - 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(); - } +pub(crate) fn handle_interrupt() { + let mut guard = UART_DEVICE.lock(); - 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"); + drop(guard); + crate::console::CONSOLE_WAKER.lock().wake(); +} - (SERIAL_IRQ, serial_handler) +#[cfg(feature = "pci")] +pub(crate) fn register_handler(handlers: &mut InterruptHandlerMap) { + super::interrupts::add_irq_name(SERIAL_IRQ, "COM1"); + handlers + .entry(SERIAL_IRQ) + .or_default() + .push_back(handle_interrupt); } diff --git a/src/drivers/console/mmio.rs b/src/drivers/console/mmio.rs index 7bef82ea95..d6eb885026 100644 --- a/src/drivers/console/mmio.rs +++ b/src/drivers/console/mmio.rs @@ -2,17 +2,16 @@ 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::{InterruptHandlerMap, 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 +36,6 @@ impl VirtioConsoleDriver { com_cfg: ComCfg::new(registers), isr_stat, notif_cfg, - irq, recv_vq: RxQueue::new(), send_vq: TxQueue::new(), }) @@ -52,9 +50,11 @@ impl VirtioConsoleDriver { dev_id: u16, registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, + handlers: &mut InterruptHandlerMap, ) -> 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 3bf4e2f0c2..c46fddd7e0 100644 --- a/src/drivers/console/mod.rs +++ b/src/drivers/console/mod.rs @@ -40,7 +40,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, InterruptHandlerMap, InterruptLine}; use crate::errno::Errno; use crate::mm::device_alloc::DeviceAlloc; @@ -262,17 +262,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" } @@ -304,7 +299,11 @@ impl VirtioConsoleDriver { self.com_cfg.set_failed(); } - pub fn init_dev(&mut self) -> Result<(), VirtioConsoleError> { + pub fn init_dev( + &mut self, + handlers: &mut InterruptHandlerMap, + irq: Option, + ) -> Result<(), VirtioConsoleError> { // Reset self.com_cfg.reset_dev(); @@ -369,6 +368,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 640c474502..b8f611648a 100644 --- a/src/drivers/console/pci.rs +++ b/src/drivers/console/pci.rs @@ -3,6 +3,7 @@ use virtio::console::Config; use volatile::VolatileRef; use crate::arch::kernel::pci::PciConfigRegion; +use crate::drivers::InterruptHandlerMap; use crate::drivers::console::{ConsoleDevCfg, RxQueue, TxQueue, VirtioConsoleDriver}; use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; @@ -47,7 +48,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 +58,7 @@ impl VirtioConsoleDriver { /// Returns a driver instance of VirtioConsoleDriver. pub(crate) fn init( device: &PciDevice, + handlers: &mut InterruptHandlerMap, ) -> Result { // enable bus master mode device.set_command(CommandRegister::BUS_MASTER_ENABLE); @@ -76,7 +77,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..83afe9f119 100644 --- a/src/drivers/fs/mmio.rs +++ b/src/drivers/fs/mmio.rs @@ -4,17 +4,16 @@ 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::{InterruptHandlerMap, 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 +39,6 @@ impl VirtioFsDriver { isr_stat, notif_cfg, vqueues: Vec::new(), - irq, }) } @@ -53,9 +51,11 @@ impl VirtioFsDriver { dev_id: u16, registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, + handlers: &mut InterruptHandlerMap, ) -> 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 435fae9f1d..ddb5e506e0 100644 --- a/src/drivers/fs/mod.rs +++ b/src/drivers/fs/mod.rs @@ -30,7 +30,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 +45,7 @@ use crate::drivers::virtio::virtqueue::split::SplitVq; use crate::drivers::virtio::virtqueue::{ AvailBufferToken, BufferElem, BufferType, VirtQueue, Virtq, }; +use crate::drivers::{Driver, InterruptHandlerMap}; use crate::errno::Errno; use crate::fs::virtio_fs::{self, Rsp, RspHeader, VirtioFsError, VirtioFsInterface}; use crate::mm::device_alloc::DeviceAlloc; @@ -66,7 +70,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 +89,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 InterruptHandlerMap, + irq: Option, + ) -> Result<(), VirtioFsInitError> { // Reset self.com_cfg.reset_dev(); @@ -152,6 +159,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(); @@ -260,10 +273,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 98c5046644..0605e111b9 100644 --- a/src/drivers/fs/pci.rs +++ b/src/drivers/fs/pci.rs @@ -3,6 +3,7 @@ use alloc::vec::Vec; use volatile::VolatileRef; use crate::arch::kernel::pci::PciConfigRegion; +use crate::drivers::InterruptHandlerMap; use crate::drivers::fs::{FsDevCfg, VirtioFsDriver}; use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; @@ -49,12 +50,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 InterruptHandlerMap, + ) -> Result { let mut drv = match pci::map_caps(device) { Ok(caps) => match VirtioFsDriver::new(caps, device) { Ok(driver) => driver, @@ -69,7 +72,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 ee74b0c634..63277722e3 100644 --- a/src/drivers/mod.rs +++ b/src/drivers/mod.rs @@ -17,12 +17,14 @@ 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"))] pub(crate) type InterruptLine = u8; -pub(crate) type InterruptHandlerQueue = VecDeque; +pub(crate) type InterruptHandlerMap = HashMap, RandomState>; /// A common error module for drivers. /// [DriverError](error::DriverError) values will be @@ -66,24 +68,34 @@ 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(feature = "pci", target_arch = "x86_64"))] + crate::arch::kernel::serial::register_handler(&mut handlers); + #[cfg(all(not(feature = "pci"), feature = "virtio", target_arch = "x86_64"))] - crate::arch::kernel::mmio::init_drivers(); + crate::arch::kernel::mmio::init_drivers(&mut handlers); #[cfg(all(not(feature = "pci"), feature = "virtio", target_arch = "aarch64"))] - crate::arch::kernel::mmio::init_drivers(); + crate::arch::kernel::mmio::init_drivers(&mut handlers); #[cfg(target_arch = "riscv64")] - crate::arch::kernel::init_drivers(); + crate::arch::kernel::init_drivers(&mut handlers); - crate::arch::kernel::interrupts::install_handlers(); + crate::arch::kernel::interrupts::install_handlers(handlers); } diff --git a/src/drivers/net/gem.rs b/src/drivers/net/gem.rs index a1ae9ae3af..fb0edc5b67 100644 --- a/src/drivers/net/gem.rs +++ b/src/drivers/net/gem.rs @@ -18,7 +18,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, InterruptHandlerMap}; use crate::executor::network::wake_network_waker; use crate::mm::device_alloc::DeviceAlloc; @@ -207,7 +207,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 +315,6 @@ impl TxFields { } impl Driver for GEMDriver { - fn get_interrupt_number(&self) -> InterruptLine { - self.irq - } - fn get_name(&self) -> &'static str { "gem" } @@ -574,6 +569,7 @@ pub fn init_device( irq: u8, phy_addr: u32, mac: [u8; 6], + handlers: &mut InterruptHandlerMap, ) -> Result { debug!("Init GEM at {gem_base:p}"); @@ -806,9 +802,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 b8b483d13d..6964b0cf95 100644 --- a/src/drivers/net/rtl8139.rs +++ b/src/drivers/net/rtl8139.rs @@ -9,7 +9,7 @@ use core::mem::ManuallyDrop; use core::ptr::NonNull; use endian_num::{le16, le32, le64}; -use pci_types::{Bar, CommandRegister, InterruptLine, MAX_BARS}; +use pci_types::{Bar, CommandRegister, MAX_BARS}; use smoltcp::phy::DeviceCapabilities; use thiserror::Error; use volatile::access::{NoAccess, ReadOnly, ReadWrite}; @@ -17,10 +17,10 @@ use volatile::{VolatileFieldAccess, VolatilePtr, VolatileRef, map_field}; use crate::arch::kernel::interrupts::*; use crate::arch::kernel::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, InterruptHandlerMap}; use crate::executor::network::wake_network_waker; use crate::mm::device_alloc::DeviceAlloc; @@ -480,7 +480,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 +697,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 +743,7 @@ impl Drop for RTL8139Driver { pub(crate) fn init_device( device: &PciDevice, + handlers: &mut InterruptHandlerMap, ) -> Result { let irq = device.get_irq().unwrap(); let mut regs = None; @@ -889,12 +885,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..ceb6b7c41b 100644 --- a/src/drivers/net/virtio/mmio.rs +++ b/src/drivers/net/virtio/mmio.rs @@ -2,17 +2,16 @@ 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::{InterruptHandlerMap, 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 +38,6 @@ impl VirtioNetDriver { notif_cfg, inner: Uninit, num_vqs: 0, - irq, checksums: ChecksumCapabilities::default(), }) } @@ -53,9 +51,12 @@ impl VirtioNetDriver { dev_id: u16, registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, + handlers: &mut InterruptHandlerMap, ) -> 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 3faf4d2fe6..3d43ae375c 100644 --- a/src/drivers/net/virtio/mod.rs +++ b/src/drivers/net/virtio/mod.rs @@ -46,7 +46,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, InterruptHandlerMap, InterruptLine}; use crate::executor::network::wake_network_waker; use crate::mm::device_alloc::DeviceAlloc; @@ -248,7 +248,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. @@ -595,10 +594,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" } @@ -754,7 +749,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 InterruptHandlerMap, + irq: Option, + ) -> Result, VirtioNetError> { // Reset self.com_cfg.reset_dev(); @@ -837,6 +836,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(); @@ -861,7 +865,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 83cf8a0094..f2b217438e 100644 --- a/src/drivers/net/virtio/pci.rs +++ b/src/drivers/net/virtio/pci.rs @@ -4,6 +4,7 @@ use volatile::VolatileRef; use super::{Init, Uninit}; use crate::arch::kernel::pci::PciConfigRegion; +use crate::drivers::InterruptHandlerMap; use crate::drivers::net::virtio::{NetDevCfg, VirtioNetDriver}; use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; @@ -51,7 +52,6 @@ impl VirtioNetDriver { notif_cfg, inner: Uninit, num_vqs: 0, - irq: device.get_irq().unwrap(), checksums: ChecksumCapabilities::default(), }) } @@ -66,6 +66,7 @@ impl VirtioNetDriver { /// [VirtioNetDriver](structs.virtionetdriver.html) or an [VirtioError](enums.virtioerror.html). pub(crate) fn init( device: &PciDevice, + handlers: &mut InterruptHandlerMap, ) -> Result, VirtioError> { // enable bus master mode device.set_command(CommandRegister::BUS_MASTER_ENABLE); @@ -84,7 +85,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 b131965ec6..f2a93221c9 100644 --- a/src/drivers/pci.rs +++ b/src/drivers/pci.rs @@ -3,8 +3,6 @@ use alloc::vec::Vec; use core::fmt; -use ahash::RandomState; -use hashbrown::HashMap; #[cfg(any( feature = "virtio-fs", feature = "virtio-vsock", @@ -22,6 +20,9 @@ use pci_types::{ use crate::arch::kernel::pci::PciConfigRegion; #[cfg(feature = "virtio-console")] use crate::console::IoDevice; +#[allow(unused_imports)] +use crate::drivers::Driver; +use crate::drivers::InterruptHandlerMap; #[cfg(feature = "virtio-console")] use crate::drivers::console::{VirtioConsoleDriver, VirtioUART}; #[cfg(feature = "virtio-fs")] @@ -37,8 +38,6 @@ use crate::drivers::virtio::transport::pci as pci_virtio; use crate::drivers::virtio::transport::pci::VirtioDriver; #[cfg(feature = "virtio-vsock")] use crate::drivers::vsock::VirtioVsockDriver; -#[allow(unused_imports)] -use crate::drivers::{Driver, InterruptHandlerQueue}; #[cfg(any(feature = "rtl8139", feature = "virtio-net"))] use crate::executor::device::NETWORK_DEVICE; use crate::init_cell::InitCell; @@ -365,90 +364,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::arch::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 +400,11 @@ pub(crate) fn get_filesystem_driver() -> Option<&'static InterruptTicketMutex { register_driver(PciDriver::VirtioConsole(InterruptTicketMutex::new(*drv))); @@ -529,11 +454,12 @@ 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}"), } } + PCI_DRIVERS.finalize(); }); } diff --git a/src/drivers/virtio/transport/mmio.rs b/src/drivers/virtio/transport/mmio.rs index 9c31233cc3..3a5737ff30 100644 --- a/src/drivers/virtio/transport/mmio.rs +++ b/src/drivers/virtio/transport/mmio.rs @@ -16,7 +16,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 +27,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::{InterruptHandlerMap, InterruptLine}; pub struct VqCfgHandler<'a> { vq_index: u16, @@ -335,6 +335,7 @@ pub(crate) enum VirtioDriver { pub(crate) fn init_device( registers: VolatileRef<'static, DeviceRegisters>, irq_no: InterruptLine, + handlers: &mut InterruptHandlerMap, ) -> Result { let dev_id: u16 = 0; @@ -348,7 +349,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."); @@ -368,7 +369,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::kernel::interrupts::add_irq_name(irq_no, "virtio"); @@ -381,7 +382,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."); @@ -396,7 +397,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 661a68281e..4fc90bc5d6 100644 --- a/src/drivers/virtio/transport/pci.rs +++ b/src/drivers/virtio/transport/pci.rs @@ -19,6 +19,7 @@ use volatile::access::ReadOnly; use volatile::{VolatilePtr, VolatileRef}; use crate::arch::kernel::pci::PciConfigRegion; +use crate::drivers::InterruptHandlerMap; #[cfg(feature = "virtio-console")] use crate::drivers::console::VirtioConsoleDriver; use crate::drivers::error::DriverError; @@ -629,8 +630,22 @@ pub(crate) fn map_caps(device: &PciDevice) -> Result`] reference, allowing access to the capabilities /// list of the given device through [map_caps]. +#[cfg_attr( + not(any( + feature = "virtio-console", + feature = "virtio-fs", + all( + not(all(target_arch = "riscv64", feature = "gem-net", not(feature = "pci"))), + not(feature = "rtl8139"), + feature = "virtio-net", + ), + feature = "virtio-vsock" + )), + expect(unused_variables) +)] pub(crate) fn init_device( device: &PciDevice, + handlers: &mut InterruptHandlerMap, ) -> Result { let device_id = device.device_id(); @@ -649,7 +664,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."); @@ -670,7 +685,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(); @@ -690,7 +705,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."); @@ -708,7 +723,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 f017d517b8..02980e35c5 100644 --- a/src/drivers/vsock/mmio.rs +++ b/src/drivers/vsock/mmio.rs @@ -2,17 +2,16 @@ use virtio::mmio::{DeviceRegisters, DeviceRegistersVolatileFieldAccess}; use virtio::vsock::Config; use volatile::VolatileRef; -use crate::drivers::InterruptLine; 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::{InterruptHandlerMap, 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 +36,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 +51,11 @@ impl VirtioVsockDriver { dev_id: u16, registers: VolatileRef<'static, DeviceRegisters>, irq: InterruptLine, + handlers: &mut InterruptHandlerMap, ) -> 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 88fafd16cd..49a4c075c7 100644 --- a/src/drivers/vsock/mod.rs +++ b/src/drivers/vsock/mod.rs @@ -20,7 +20,10 @@ use volatile::access::ReadOnly; use super::virtio::virtqueue::VirtQueue; use crate::config::{VIRTIO_MAX_QUEUE_SIZE, VSOCK_PACKET_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 +34,7 @@ use crate::drivers::virtio::virtqueue::split::SplitVq; use crate::drivers::virtio::virtqueue::{ AvailBufferToken, BufferElem, BufferType, UsedBufferToken, Virtq, }; +use crate::drivers::{Driver, InterruptHandlerMap}; use crate::mm::device_alloc::DeviceAlloc; fn fill_queue(vq: &mut VirtQueue, num_packets: u16, packet_size: u32) { @@ -260,7 +264,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 +271,6 @@ pub(crate) struct VirtioVsockDriver { } impl Driver for VirtioVsockDriver { - fn get_interrupt_number(&self) -> InterruptLine { - self.irq - } - fn get_name(&self) -> &'static str { "virtio" } @@ -323,7 +322,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 InterruptHandlerMap, + irq: Option, + ) -> Result<(), VirtioVsockError> { // Reset self.com_cfg.reset_dev(); @@ -399,6 +402,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 7b1ad9c33f..143075c397 100644 --- a/src/drivers/vsock/pci.rs +++ b/src/drivers/vsock/pci.rs @@ -1,6 +1,7 @@ use volatile::VolatileRef; use crate::arch::kernel::pci::PciConfigRegion; +use crate::drivers::InterruptHandlerMap; use crate::drivers::pci::PciDevice; use crate::drivers::virtio::error::{self, VirtioError}; use crate::drivers::virtio::transport::pci; @@ -46,7 +47,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 +58,7 @@ impl VirtioVsockDriver { /// Returns a driver instance of VirtioVsockDriver. pub(crate) fn init( device: &PciDevice, + handlers: &mut InterruptHandlerMap, ) -> Result { let mut drv = match pci::map_caps(device) { Ok(caps) => match VirtioVsockDriver::new(caps, device) { @@ -73,7 +74,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!");