diff --git a/build/src/main.rs b/build/src/main.rs index 86918c76a..e4548ddf0 100644 --- a/build/src/main.rs +++ b/build/src/main.rs @@ -55,7 +55,7 @@ const COMMON_ARGS: &[&str] = &[ "-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-netdev", - "user,id=net01,hostfwd=tcp::30033-:22,hostfwd=tcp::30088-:8080", + "user,id=net01,hostfwd=tcp::30133-:22,hostfwd=tcp::31088-:8080", "-object", "filter-dump,id=filter0,netdev=net01,file=virtio-net.pcap", ]; diff --git a/framework/jinux-frame/src/arch/x86/device/serial.rs b/framework/jinux-frame/src/arch/x86/device/serial.rs index c2da61809..59f6cb0b7 100644 --- a/framework/jinux-frame/src/arch/x86/device/serial.rs +++ b/framework/jinux-frame/src/arch/x86/device/serial.rs @@ -2,7 +2,7 @@ use crate::arch::x86::device::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess}; use crate::sync::SpinLock; -use crate::trap::IrqAllocateHandle; +use crate::trap::IrqLine; use alloc::{sync::Arc, vec::Vec}; use log::debug; use spin::Once; @@ -25,7 +25,7 @@ static SERIAL_MODEM_CTRL: IoPort = unsafe { IoPort::new(SERIAL_DATA_PORT + 4) }; static SERIAL_LINE_STS: IoPort = unsafe { IoPort::new(SERIAL_DATA_PORT + 5) }; -static CONSOLE_IRQ_CALLBACK: Once> = Once::new(); +static CONSOLE_IRQ_CALLBACK: Once> = Once::new(); static SERIAL_INPUT_CALLBACKS: SpinLock>> = SpinLock::new(Vec::new()); diff --git a/framework/jinux-frame/src/arch/x86/iommu/fault.rs b/framework/jinux-frame/src/arch/x86/iommu/fault.rs index 3f55fe6fe..dda652280 100644 --- a/framework/jinux-frame/src/arch/x86/iommu/fault.rs +++ b/framework/jinux-frame/src/arch/x86/iommu/fault.rs @@ -7,7 +7,7 @@ use spin::Once; use trapframe::TrapFrame; use volatile::{access::ReadWrite, Volatile}; -use crate::{trap::IrqAllocateHandle, vm::Vaddr}; +use crate::{trap::IrqLine, vm::Vaddr}; use super::remapping::Capability; @@ -21,7 +21,7 @@ pub struct FaultEventRegisters { upper_address: Volatile<&'static mut u32, ReadWrite>, recordings: Vec>, - fault_irq: IrqAllocateHandle, + fault_irq: IrqLine, } impl FaultEventRegisters { @@ -47,7 +47,7 @@ impl FaultEventRegisters { let mut data = Volatile::new(&mut *((base_register_vaddr + 0x3c) as *mut u32)); let mut address = Volatile::new(&mut *((base_register_vaddr + 0x40) as *mut u32)); let upper_address = Volatile::new(&mut *((base_register_vaddr + 0x44) as *mut u32)); - let mut fault_irq = crate::trap::allocate_irq().unwrap(); + let mut fault_irq = crate::trap::IrqLine::alloc().unwrap(); // Set page fault interrupt vector and address data.write(fault_irq.num() as u32); diff --git a/framework/jinux-frame/src/arch/x86/irq.rs b/framework/jinux-frame/src/arch/x86/irq.rs index 82af30394..9107d478a 100644 --- a/framework/jinux-frame/src/arch/x86/irq.rs +++ b/framework/jinux-frame/src/arch/x86/irq.rs @@ -1,12 +1,16 @@ use crate::sync::Mutex; -use alloc::vec::Vec; +use alloc::{boxed::Box, fmt::Debug, sync::Arc, vec::Vec}; use spin::Once; +use trapframe::TrapFrame; -use crate::{trap::IrqLine, util::recycle_allocator::RecycleAllocator}; +use crate::{ + sync::{SpinLock, SpinLockGuard}, + util::recycle_allocator::RecycleAllocator, +}; /// The IRQ numbers which are not using -pub(crate) static NOT_USING_IRQ: Mutex = - Mutex::new(RecycleAllocator::with_start_max(32, 256)); +pub(crate) static NOT_USING_IRQ: SpinLock = + SpinLock::new(RecycleAllocator::with_start_max(32, 256)); pub(crate) static IRQ_LIST: Once> = Once::new(); @@ -15,7 +19,7 @@ pub(crate) fn init() { for i in 0..256 { list.push(IrqLine { irq_num: i as u8, - callback_list: Mutex::new(Vec::new()), + callback_list: SpinLock::new(Vec::new()), }); } IRQ_LIST.call_once(|| list); @@ -32,3 +36,97 @@ pub(crate) fn disable_local() { pub(crate) fn is_local_enabled() -> bool { x86_64::instructions::interrupts::are_enabled() } + +static ID_ALLOCATOR: Mutex = Mutex::new(RecycleAllocator::new()); + +pub struct CallbackElement { + function: Box, + id: usize, +} + +impl CallbackElement { + pub fn call(&self, element: &TrapFrame) { + self.function.call((element,)); + } +} + +impl Debug for CallbackElement { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("CallbackElement") + .field("id", &self.id) + .finish() + } +} + +/// An interrupt request (IRQ) line. +#[derive(Debug)] +pub(crate) struct IrqLine { + pub(crate) irq_num: u8, + pub(crate) callback_list: SpinLock>, +} + +impl IrqLine { + /// Acquire an interrupt request line. + /// + /// # Safety + /// + /// This function is marked unsafe as manipulating interrupt lines is + /// considered a dangerous operation. + pub unsafe fn acquire(irq_num: u8) -> Arc<&'static Self> { + Arc::new(IRQ_LIST.get().unwrap().get(irq_num as usize).unwrap()) + } + + /// Get the IRQ number. + pub fn num(&self) -> u8 { + self.irq_num + } + + pub fn callback_list(&self) -> SpinLockGuard<'_, alloc::vec::Vec> { + self.callback_list.lock() + } + + /// Register a callback that will be invoked when the IRQ is active. + /// + /// A handle to the callback is returned. Dropping the handle + /// automatically unregisters the callback. + /// + /// For each IRQ line, multiple callbacks may be registered. + pub fn on_active(&self, callback: F) -> IrqCallbackHandle + where + F: Fn(&TrapFrame) + Sync + Send + 'static, + { + let allocate_id = ID_ALLOCATOR.lock().alloc(); + self.callback_list.lock().push(CallbackElement { + function: Box::new(callback), + id: allocate_id, + }); + IrqCallbackHandle { + irq_num: self.irq_num, + id: allocate_id, + } + } +} + +/// The handle to a registered callback for a IRQ line. +/// +/// When the handle is dropped, the callback will be unregistered automatically. +#[must_use] +#[derive(Debug)] +pub struct IrqCallbackHandle { + irq_num: u8, + id: usize, +} + +impl Drop for IrqCallbackHandle { + fn drop(&mut self) { + let mut a = IRQ_LIST + .get() + .unwrap() + .get(self.irq_num as usize) + .unwrap() + .callback_list + .lock(); + a.retain(|item| if (*item).id == self.id { false } else { true }); + ID_ALLOCATOR.lock().dealloc(self.id); + } +} diff --git a/framework/jinux-frame/src/arch/x86/kernel/pic.rs b/framework/jinux-frame/src/arch/x86/kernel/pic.rs index 5cc17952b..7a29a1434 100644 --- a/framework/jinux-frame/src/arch/x86/kernel/pic.rs +++ b/framework/jinux-frame/src/arch/x86/kernel/pic.rs @@ -1,6 +1,5 @@ use crate::arch::x86::device::io_port::{IoPort, WriteOnlyAccess}; -use crate::trap::allocate_target_irq; -use crate::trap::IrqAllocateHandle; +use crate::trap::IrqLine; use core::sync::atomic::Ordering::Relaxed; use core::sync::atomic::{AtomicBool, AtomicU8}; @@ -22,7 +21,7 @@ use log::info; lazy_static! { /// store the irq, although we have APIC for manage interrupts /// but something like serial still need pic for register interrupts - static ref IRQ_LOCK : Mutex> = Mutex::new(Vec::new()); + static ref IRQ_LOCK : Mutex> = Mutex::new(Vec::new()); } static MASK_MASTER: AtomicU8 = AtomicU8::new(0x00); @@ -46,11 +45,11 @@ pub fn init() { } /// allocate irq, for example, if timer need IRQ0, it will return IrqAllocateHandle with irq num: IRQ_OFFSET+0 -pub fn allocate_irq(index: u8) -> Option { +pub fn allocate_irq(index: u8) -> Option { if index >= 16 { return None; } - if let Ok(irq) = allocate_target_irq(IRQ_OFFSET + index) { + if let Ok(irq) = IrqLine::alloc_specific(IRQ_OFFSET + index) { if index >= 8 { MASK_SLAVE.fetch_or(1 << (index - 8), Relaxed); } else { diff --git a/framework/jinux-frame/src/arch/x86/timer/apic.rs b/framework/jinux-frame/src/arch/x86/timer/apic.rs index a9ce87ec2..b45026689 100644 --- a/framework/jinux-frame/src/arch/x86/timer/apic.rs +++ b/framework/jinux-frame/src/arch/x86/timer/apic.rs @@ -9,6 +9,7 @@ use trapframe::TrapFrame; use x86::cpuid::cpuid; use x86::msr::{wrmsr, IA32_TSC_DEADLINE}; +use crate::arch::irq::IrqLine; use crate::{ arch::x86::kernel::{ apic::{DivideConfig, APIC_INSTANCE}, @@ -63,7 +64,7 @@ fn tsc_mode_init() { fn periodic_mode_init() { let mut apic_lock = APIC_INSTANCE.get().unwrap().lock(); - let handle = unsafe { crate::trap::IrqLine::acquire(super::TIMER_IRQ_NUM) }; + let handle = unsafe { IrqLine::acquire(super::TIMER_IRQ_NUM) }; let a = handle.on_active(init_function); // divide by 64 apic_lock.set_timer_div_config(DivideConfig::Divide64); diff --git a/framework/jinux-frame/src/arch/x86/timer/mod.rs b/framework/jinux-frame/src/arch/x86/timer/mod.rs index bff0a8a1a..e7ff9416d 100644 --- a/framework/jinux-frame/src/arch/x86/timer/mod.rs +++ b/framework/jinux-frame/src/arch/x86/timer/mod.rs @@ -12,14 +12,14 @@ use trapframe::TrapFrame; use crate::arch::x86::kernel; use crate::config::TIMER_FREQ; use crate::sync::SpinLock; -use crate::trap::IrqAllocateHandle; +use crate::trap::IrqLine; use self::apic::APIC_TIMER_CALLBACK; pub const TIMER_IRQ_NUM: u8 = 32; pub static TICK: AtomicU64 = AtomicU64::new(0); -static TIMER_IRQ: Once = Once::new(); +static TIMER_IRQ: Once = Once::new(); pub fn init() { TIMEOUT_LIST.call_once(|| SpinLock::new(BinaryHeap::new())); @@ -29,7 +29,7 @@ pub fn init() { pit::init(); } let mut timer_irq = - crate::trap::allocate_target_irq(TIMER_IRQ_NUM).expect("Timer irq Allocate error"); + crate::trap::IrqLine::alloc_specific(TIMER_IRQ_NUM).expect("Timer irq Allocate error"); timer_irq.on_active(timer_callback); TIMER_IRQ.call_once(|| timer_irq); } diff --git a/framework/jinux-frame/src/bus/pci/capability/msix.rs b/framework/jinux-frame/src/bus/pci/capability/msix.rs index 86c8c4fb7..608d4f878 100644 --- a/framework/jinux-frame/src/bus/pci/capability/msix.rs +++ b/framework/jinux-frame/src/bus/pci/capability/msix.rs @@ -6,7 +6,7 @@ use crate::{ common_device::PciCommonDevice, device_info::PciDeviceLocation, }, - trap::IrqAllocateHandle, + trap::IrqLine, vm::VmIo, }; @@ -24,7 +24,7 @@ pub struct CapabilityMsixData { pending_table_bar: Arc, table_offset: usize, pending_table_offset: usize, - irqs: Vec>, + irqs: Vec>, } impl Clone for CapabilityMsixData { @@ -109,9 +109,9 @@ impl CapabilityMsixData { // disable INTx, enable Bus master. dev.set_command(dev.command() | Command::INTERRUPT_DISABLE | Command::BUS_MASTER); - let mut irq_allocate_handles = Vec::with_capacity(table_size as usize); + let mut irqs = Vec::with_capacity(table_size as usize); for i in 0..table_size { - irq_allocate_handles.push(None); + irqs.push(None); } Self { @@ -120,7 +120,7 @@ impl CapabilityMsixData { table_size: (dev.location().read16(cap_ptr + 2) & 0b11_1111_1111) + 1, table_bar, pending_table_bar: pba_bar, - irqs: irq_allocate_handles, + irqs, table_offset: table_offset, pending_table_offset: pba_offset, } @@ -131,7 +131,7 @@ impl CapabilityMsixData { (self.loc.read16(self.ptr + 2) & 0b11_1111_1111) + 1 } - pub fn set_interrupt_vector(&mut self, handle: IrqAllocateHandle, index: u16) { + pub fn set_interrupt_vector(&mut self, handle: IrqLine, index: u16) { if index >= self.table_size { return; } @@ -150,7 +150,7 @@ impl CapabilityMsixData { .unwrap(); } - pub fn irq_mut(&mut self, index: usize) -> Option<&mut IrqAllocateHandle> { + pub fn irq_mut(&mut self, index: usize) -> Option<&mut IrqLine> { self.irqs[index].as_mut() } } diff --git a/framework/jinux-frame/src/lib.rs b/framework/jinux-frame/src/lib.rs index 6c88ed054..c5cf5fb46 100644 --- a/framework/jinux-frame/src/lib.rs +++ b/framework/jinux-frame/src/lib.rs @@ -38,8 +38,8 @@ pub use self::cpu::CpuLocal; pub use self::error::Error; pub use self::prelude::Result; use alloc::vec::Vec; +use arch::irq::{IrqCallbackHandle, IrqLine}; use core::{mem, panic::PanicInfo}; -use trap::{IrqCallbackHandle, IrqLine}; use trapframe::TrapFrame; static mut IRQ_CALLBACK_LIST: Vec = Vec::new(); diff --git a/framework/jinux-frame/src/trap/irq.rs b/framework/jinux-frame/src/trap/irq.rs index e61642abd..93e48a13f 100644 --- a/framework/jinux-frame/src/trap/irq.rs +++ b/framework/jinux-frame/src/trap/irq.rs @@ -1,46 +1,46 @@ -use crate::arch::irq; -use crate::arch::irq::{IRQ_LIST, NOT_USING_IRQ}; -use crate::sync::{Mutex, MutexGuard}; +use crate::arch::irq::{self, IrqCallbackHandle, NOT_USING_IRQ}; use crate::task::{disable_preempt, DisablePreemptGuard}; -use crate::util::recycle_allocator::RecycleAllocator; use crate::{prelude::*, Error}; use core::fmt::Debug; use trapframe::TrapFrame; -pub fn allocate_irq() -> Result { - let irq_num = NOT_USING_IRQ.lock().alloc(); - if irq_num == usize::MAX { - Err(Error::NotEnoughResources) - } else { - Ok(IrqAllocateHandle::new(irq_num as u8)) - } -} - -pub(crate) fn allocate_target_irq(target_irq: u8) -> Result { - if NOT_USING_IRQ.lock().get_target(target_irq as usize) { - Ok(IrqAllocateHandle::new(target_irq)) - } else { - Err(Error::NotEnoughResources) - } -} - -/// The handle to a allocate irq number between [32,256), used in std and other parts in jinux +/// An Interrupt ReQuest(IRQ) line. User can use `alloc` or `alloc_specific` to get specific IRQ line. /// -/// When the handle is dropped, all the callback in this will be unregistered automatically. +/// The IRQ number is guaranteed to be external IRQ number and user can register callback functions to this IRQ resource. +/// When this resrouce is dropped, all the callback in this will be unregistered automatically. #[derive(Debug)] #[must_use] -pub struct IrqAllocateHandle { +pub struct IrqLine { irq_num: u8, - irq: Arc<&'static IrqLine>, + irq: Arc<&'static irq::IrqLine>, callbacks: Vec, } -impl IrqAllocateHandle { +impl IrqLine { + pub fn alloc_specific(irq: u8) -> Result { + if NOT_USING_IRQ.lock().get_target(irq as usize) { + Ok(Self::new(irq)) + } else { + Err(Error::NotEnoughResources) + } + } + + pub fn alloc() -> Result { + let irq_num = NOT_USING_IRQ.lock().alloc(); + if irq_num == usize::MAX { + Err(Error::NotEnoughResources) + } else { + Ok(Self::new(irq_num as u8)) + } + } + fn new(irq_num: u8) -> Self { + // Safety: The IRQ number is allocated through `RecycleAllocator`, and it is guaranteed that the + // IRQ is not one of the important IRQ like cpu exception IRQ. Self { irq_num, - irq: unsafe { IrqLine::acquire(irq_num) }, + irq: unsafe { irq::IrqLine::acquire(irq_num) }, callbacks: Vec::new(), } } @@ -65,7 +65,7 @@ impl IrqAllocateHandle { } } -impl Clone for IrqAllocateHandle { +impl Clone for IrqLine { fn clone(&self) -> Self { Self { irq_num: self.irq_num.clone(), @@ -75,7 +75,7 @@ impl Clone for IrqAllocateHandle { } } -impl Drop for IrqAllocateHandle { +impl Drop for IrqLine { fn drop(&mut self) { if Arc::strong_count(&self.irq) == 1 { NOT_USING_IRQ.lock().dealloc(self.irq_num as usize); @@ -83,101 +83,6 @@ impl Drop for IrqAllocateHandle { } } -static ID_ALLOCATOR: Mutex = Mutex::new(RecycleAllocator::new()); - -pub struct CallbackElement { - function: Box, - id: usize, -} - -impl CallbackElement { - pub fn call(&self, element: &TrapFrame) { - self.function.call((element,)); - } -} - -impl Debug for CallbackElement { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_struct("CallbackElement") - .field("id", &self.id) - .finish() - } -} - -/// An interrupt request (IRQ) line. -#[derive(Debug)] -pub(crate) struct IrqLine { - pub(crate) irq_num: u8, - pub(crate) callback_list: Mutex>, -} - -impl IrqLine { - /// Acquire an interrupt request line. - /// - /// # Safety - /// - /// This function is marked unsafe as manipulating interrupt lines is - /// considered a dangerous operation. - pub unsafe fn acquire(irq_num: u8) -> Arc<&'static Self> { - Arc::new(IRQ_LIST.get().unwrap().get(irq_num as usize).unwrap()) - } - - /// Get the IRQ number. - pub fn num(&self) -> u8 { - self.irq_num - } - - pub fn callback_list(&self) -> MutexGuard<'_, alloc::vec::Vec> { - self.callback_list.lock() - } - - /// Register a callback that will be invoked when the IRQ is active. - /// - /// A handle to the callback is returned. Dropping the handle - /// automatically unregisters the callback. - /// - /// For each IRQ line, multiple callbacks may be registered. - pub fn on_active(&self, callback: F) -> IrqCallbackHandle - where - F: Fn(&TrapFrame) + Sync + Send + 'static, - { - let allocate_id = ID_ALLOCATOR.lock().alloc(); - self.callback_list.lock().push(CallbackElement { - function: Box::new(callback), - id: allocate_id, - }); - IrqCallbackHandle { - irq_num: self.irq_num, - id: allocate_id, - } - } -} - -/// The handle to a registered callback for a IRQ line. -/// -/// When the handle is dropped, the callback will be unregistered automatically. -#[must_use] -#[derive(Debug)] -pub struct IrqCallbackHandle { - irq_num: u8, - id: usize, - // cursor: CursorMut<'a, Box> -} - -impl Drop for IrqCallbackHandle { - fn drop(&mut self) { - let mut a = IRQ_LIST - .get() - .unwrap() - .get(self.irq_num as usize) - .unwrap() - .callback_list - .lock(); - a.retain(|item| if (*item).id == self.id { false } else { true }); - ID_ALLOCATOR.lock().dealloc(self.id); - } -} - /// Disable all IRQs on the current CPU (i.e., locally). /// /// This function returns a guard object, which will automatically enable local IRQs again when diff --git a/framework/jinux-frame/src/trap/mod.rs b/framework/jinux-frame/src/trap/mod.rs index 8bc6fc501..dc6c11878 100644 --- a/framework/jinux-frame/src/trap/mod.rs +++ b/framework/jinux-frame/src/trap/mod.rs @@ -2,8 +2,7 @@ mod handler; mod irq; pub(crate) use self::handler::call_irq_callback_functions; -pub use self::irq::{allocate_irq, disable_local, DisabledLocalIrqGuard, IrqAllocateHandle}; -pub(crate) use self::irq::{allocate_target_irq, IrqCallbackHandle, IrqLine}; +pub use self::irq::{disable_local, DisabledLocalIrqGuard, IrqLine}; pub use trapframe::TrapFrame; pub(crate) fn init() { diff --git a/services/comps/virtio/src/transport/pci/msix.rs b/services/comps/virtio/src/transport/pci/msix.rs index 179b420b1..77ceda7b9 100644 --- a/services/comps/virtio/src/transport/pci/msix.rs +++ b/services/comps/virtio/src/transport/pci/msix.rs @@ -1,5 +1,5 @@ use alloc::vec::Vec; -use jinux_frame::{bus::pci::capability::msix::CapabilityMsixData, trap::IrqAllocateHandle}; +use jinux_frame::{bus::pci::capability::msix::CapabilityMsixData, trap::IrqLine}; pub struct VirtioMsixManager { config_msix_vector: u16, @@ -17,8 +17,8 @@ impl VirtioMsixManager { pub fn new(mut msix: CapabilityMsixData) -> Self { let mut msix_vector_list: Vec = (0..msix.table_size()).collect(); for i in msix_vector_list.iter() { - let allocate_handle = jinux_frame::trap::allocate_irq().unwrap(); - msix.set_interrupt_vector(allocate_handle, *i); + let irq = jinux_frame::trap::IrqLine::alloc().unwrap(); + msix.set_interrupt_vector(irq, *i); } let config_msix_vector = msix_vector_list.pop().unwrap(); let shared_interrupt_vector = msix_vector_list.pop().unwrap(); @@ -32,7 +32,7 @@ impl VirtioMsixManager { } /// Get config space change MSI-X IRQ, this function will return the MSI-X vector and corresponding IRQ. - pub fn config_msix_irq(&mut self) -> (u16, &mut IrqAllocateHandle) { + pub fn config_msix_irq(&mut self) -> (u16, &mut IrqLine) { ( self.config_msix_vector, self.msix.irq_mut(self.config_msix_vector as usize).unwrap(), @@ -42,7 +42,7 @@ impl VirtioMsixManager { /// Get shared interrupt IRQ used by virtqueue. If a virtqueue will not send interrupt frequently. /// Then this virtqueue should use shared interrupt IRQ. /// This function will return the MSI-X vector and corresponding IRQ. - pub fn shared_interrupt_irq(&mut self) -> (u16, &mut IrqAllocateHandle) { + pub fn shared_interrupt_irq(&mut self) -> (u16, &mut IrqLine) { ( self.shared_interrupt_vector, self.msix @@ -54,7 +54,7 @@ impl VirtioMsixManager { /// Pop unused vector. If a virtqueue will send interrupt frequently. /// Then this virtqueue should use the single IRQ that this function provides. /// this function will return the MSI-X vector and corresponding IRQ. - pub fn pop_unused_irq(&mut self) -> Option<(u16, &mut IrqAllocateHandle)> { + pub fn pop_unused_irq(&mut self) -> Option<(u16, &mut IrqLine)> { let vector = self.unused_msix_vectors.pop()?; self.used_msix_vectors.push(vector); Some((vector, self.msix.irq_mut(vector as usize).unwrap()))