mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-24 18:03:25 +00:00
Rename IrqAllocateHandle and move alloc functions
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
7d5e67e368
commit
dbf5a423b1
@ -55,7 +55,7 @@ const COMMON_ARGS: &[&str] = &[
|
|||||||
"-device",
|
"-device",
|
||||||
"isa-debug-exit,iobase=0xf4,iosize=0x04",
|
"isa-debug-exit,iobase=0xf4,iosize=0x04",
|
||||||
"-netdev",
|
"-netdev",
|
||||||
"user,id=net01,hostfwd=tcp::30033-:22,hostfwd=tcp::30088-:8080",
|
"user,id=net01,hostfwd=tcp::30133-:22,hostfwd=tcp::31088-:8080",
|
||||||
"-object",
|
"-object",
|
||||||
"filter-dump,id=filter0,netdev=net01,file=virtio-net.pcap",
|
"filter-dump,id=filter0,netdev=net01,file=virtio-net.pcap",
|
||||||
];
|
];
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::arch::x86::device::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess};
|
use crate::arch::x86::device::io_port::{IoPort, ReadWriteAccess, WriteOnlyAccess};
|
||||||
use crate::sync::SpinLock;
|
use crate::sync::SpinLock;
|
||||||
use crate::trap::IrqAllocateHandle;
|
use crate::trap::IrqLine;
|
||||||
use alloc::{sync::Arc, vec::Vec};
|
use alloc::{sync::Arc, vec::Vec};
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use spin::Once;
|
use spin::Once;
|
||||||
@ -25,7 +25,7 @@ static SERIAL_MODEM_CTRL: IoPort<u8, WriteOnlyAccess> =
|
|||||||
unsafe { IoPort::new(SERIAL_DATA_PORT + 4) };
|
unsafe { IoPort::new(SERIAL_DATA_PORT + 4) };
|
||||||
static SERIAL_LINE_STS: IoPort<u8, ReadWriteAccess> = unsafe { IoPort::new(SERIAL_DATA_PORT + 5) };
|
static SERIAL_LINE_STS: IoPort<u8, ReadWriteAccess> = unsafe { IoPort::new(SERIAL_DATA_PORT + 5) };
|
||||||
|
|
||||||
static CONSOLE_IRQ_CALLBACK: Once<SpinLock<IrqAllocateHandle>> = Once::new();
|
static CONSOLE_IRQ_CALLBACK: Once<SpinLock<IrqLine>> = Once::new();
|
||||||
static SERIAL_INPUT_CALLBACKS: SpinLock<Vec<Arc<dyn Fn(u8) + Send + Sync + 'static>>> =
|
static SERIAL_INPUT_CALLBACKS: SpinLock<Vec<Arc<dyn Fn(u8) + Send + Sync + 'static>>> =
|
||||||
SpinLock::new(Vec::new());
|
SpinLock::new(Vec::new());
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use spin::Once;
|
|||||||
use trapframe::TrapFrame;
|
use trapframe::TrapFrame;
|
||||||
use volatile::{access::ReadWrite, Volatile};
|
use volatile::{access::ReadWrite, Volatile};
|
||||||
|
|
||||||
use crate::{trap::IrqAllocateHandle, vm::Vaddr};
|
use crate::{trap::IrqLine, vm::Vaddr};
|
||||||
|
|
||||||
use super::remapping::Capability;
|
use super::remapping::Capability;
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ pub struct FaultEventRegisters {
|
|||||||
upper_address: Volatile<&'static mut u32, ReadWrite>,
|
upper_address: Volatile<&'static mut u32, ReadWrite>,
|
||||||
recordings: Vec<Volatile<&'static mut u128, ReadWrite>>,
|
recordings: Vec<Volatile<&'static mut u128, ReadWrite>>,
|
||||||
|
|
||||||
fault_irq: IrqAllocateHandle,
|
fault_irq: IrqLine,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FaultEventRegisters {
|
impl FaultEventRegisters {
|
||||||
@ -47,7 +47,7 @@ impl FaultEventRegisters {
|
|||||||
let mut data = Volatile::new(&mut *((base_register_vaddr + 0x3c) as *mut u32));
|
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 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 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
|
// Set page fault interrupt vector and address
|
||||||
data.write(fault_irq.num() as u32);
|
data.write(fault_irq.num() as u32);
|
||||||
|
@ -1,12 +1,16 @@
|
|||||||
use crate::sync::Mutex;
|
use crate::sync::Mutex;
|
||||||
use alloc::vec::Vec;
|
use alloc::{boxed::Box, fmt::Debug, sync::Arc, vec::Vec};
|
||||||
use spin::Once;
|
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
|
/// The IRQ numbers which are not using
|
||||||
pub(crate) static NOT_USING_IRQ: Mutex<RecycleAllocator> =
|
pub(crate) static NOT_USING_IRQ: SpinLock<RecycleAllocator> =
|
||||||
Mutex::new(RecycleAllocator::with_start_max(32, 256));
|
SpinLock::new(RecycleAllocator::with_start_max(32, 256));
|
||||||
|
|
||||||
pub(crate) static IRQ_LIST: Once<Vec<IrqLine>> = Once::new();
|
pub(crate) static IRQ_LIST: Once<Vec<IrqLine>> = Once::new();
|
||||||
|
|
||||||
@ -15,7 +19,7 @@ pub(crate) fn init() {
|
|||||||
for i in 0..256 {
|
for i in 0..256 {
|
||||||
list.push(IrqLine {
|
list.push(IrqLine {
|
||||||
irq_num: i as u8,
|
irq_num: i as u8,
|
||||||
callback_list: Mutex::new(Vec::new()),
|
callback_list: SpinLock::new(Vec::new()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
IRQ_LIST.call_once(|| list);
|
IRQ_LIST.call_once(|| list);
|
||||||
@ -32,3 +36,97 @@ pub(crate) fn disable_local() {
|
|||||||
pub(crate) fn is_local_enabled() -> bool {
|
pub(crate) fn is_local_enabled() -> bool {
|
||||||
x86_64::instructions::interrupts::are_enabled()
|
x86_64::instructions::interrupts::are_enabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ID_ALLOCATOR: Mutex<RecycleAllocator> = Mutex::new(RecycleAllocator::new());
|
||||||
|
|
||||||
|
pub struct CallbackElement {
|
||||||
|
function: Box<dyn Fn(&TrapFrame) + Send + Sync + 'static>,
|
||||||
|
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<Vec<CallbackElement>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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<CallbackElement>> {
|
||||||
|
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<F>(&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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use crate::arch::x86::device::io_port::{IoPort, WriteOnlyAccess};
|
use crate::arch::x86::device::io_port::{IoPort, WriteOnlyAccess};
|
||||||
use crate::trap::allocate_target_irq;
|
use crate::trap::IrqLine;
|
||||||
use crate::trap::IrqAllocateHandle;
|
|
||||||
|
|
||||||
use core::sync::atomic::Ordering::Relaxed;
|
use core::sync::atomic::Ordering::Relaxed;
|
||||||
use core::sync::atomic::{AtomicBool, AtomicU8};
|
use core::sync::atomic::{AtomicBool, AtomicU8};
|
||||||
@ -22,7 +21,7 @@ use log::info;
|
|||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// store the irq, although we have APIC for manage interrupts
|
/// store the irq, although we have APIC for manage interrupts
|
||||||
/// but something like serial still need pic for register interrupts
|
/// but something like serial still need pic for register interrupts
|
||||||
static ref IRQ_LOCK : Mutex<Vec<IrqAllocateHandle>> = Mutex::new(Vec::new());
|
static ref IRQ_LOCK : Mutex<Vec<IrqLine>> = Mutex::new(Vec::new());
|
||||||
}
|
}
|
||||||
|
|
||||||
static MASK_MASTER: AtomicU8 = AtomicU8::new(0x00);
|
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
|
/// 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<IrqAllocateHandle> {
|
pub fn allocate_irq(index: u8) -> Option<IrqLine> {
|
||||||
if index >= 16 {
|
if index >= 16 {
|
||||||
return None;
|
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 {
|
if index >= 8 {
|
||||||
MASK_SLAVE.fetch_or(1 << (index - 8), Relaxed);
|
MASK_SLAVE.fetch_or(1 << (index - 8), Relaxed);
|
||||||
} else {
|
} else {
|
||||||
|
@ -9,6 +9,7 @@ use trapframe::TrapFrame;
|
|||||||
use x86::cpuid::cpuid;
|
use x86::cpuid::cpuid;
|
||||||
use x86::msr::{wrmsr, IA32_TSC_DEADLINE};
|
use x86::msr::{wrmsr, IA32_TSC_DEADLINE};
|
||||||
|
|
||||||
|
use crate::arch::irq::IrqLine;
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::x86::kernel::{
|
arch::x86::kernel::{
|
||||||
apic::{DivideConfig, APIC_INSTANCE},
|
apic::{DivideConfig, APIC_INSTANCE},
|
||||||
@ -63,7 +64,7 @@ fn tsc_mode_init() {
|
|||||||
|
|
||||||
fn periodic_mode_init() {
|
fn periodic_mode_init() {
|
||||||
let mut apic_lock = APIC_INSTANCE.get().unwrap().lock();
|
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);
|
let a = handle.on_active(init_function);
|
||||||
// divide by 64
|
// divide by 64
|
||||||
apic_lock.set_timer_div_config(DivideConfig::Divide64);
|
apic_lock.set_timer_div_config(DivideConfig::Divide64);
|
||||||
|
@ -12,14 +12,14 @@ use trapframe::TrapFrame;
|
|||||||
use crate::arch::x86::kernel;
|
use crate::arch::x86::kernel;
|
||||||
use crate::config::TIMER_FREQ;
|
use crate::config::TIMER_FREQ;
|
||||||
use crate::sync::SpinLock;
|
use crate::sync::SpinLock;
|
||||||
use crate::trap::IrqAllocateHandle;
|
use crate::trap::IrqLine;
|
||||||
|
|
||||||
use self::apic::APIC_TIMER_CALLBACK;
|
use self::apic::APIC_TIMER_CALLBACK;
|
||||||
|
|
||||||
pub const TIMER_IRQ_NUM: u8 = 32;
|
pub const TIMER_IRQ_NUM: u8 = 32;
|
||||||
pub static TICK: AtomicU64 = AtomicU64::new(0);
|
pub static TICK: AtomicU64 = AtomicU64::new(0);
|
||||||
|
|
||||||
static TIMER_IRQ: Once<IrqAllocateHandle> = Once::new();
|
static TIMER_IRQ: Once<IrqLine> = Once::new();
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
TIMEOUT_LIST.call_once(|| SpinLock::new(BinaryHeap::new()));
|
TIMEOUT_LIST.call_once(|| SpinLock::new(BinaryHeap::new()));
|
||||||
@ -29,7 +29,7 @@ pub fn init() {
|
|||||||
pit::init();
|
pit::init();
|
||||||
}
|
}
|
||||||
let mut timer_irq =
|
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.on_active(timer_callback);
|
||||||
TIMER_IRQ.call_once(|| timer_irq);
|
TIMER_IRQ.call_once(|| timer_irq);
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
common_device::PciCommonDevice,
|
common_device::PciCommonDevice,
|
||||||
device_info::PciDeviceLocation,
|
device_info::PciDeviceLocation,
|
||||||
},
|
},
|
||||||
trap::IrqAllocateHandle,
|
trap::IrqLine,
|
||||||
vm::VmIo,
|
vm::VmIo,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ pub struct CapabilityMsixData {
|
|||||||
pending_table_bar: Arc<MemoryBar>,
|
pending_table_bar: Arc<MemoryBar>,
|
||||||
table_offset: usize,
|
table_offset: usize,
|
||||||
pending_table_offset: usize,
|
pending_table_offset: usize,
|
||||||
irqs: Vec<Option<IrqAllocateHandle>>,
|
irqs: Vec<Option<IrqLine>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for CapabilityMsixData {
|
impl Clone for CapabilityMsixData {
|
||||||
@ -109,9 +109,9 @@ impl CapabilityMsixData {
|
|||||||
// disable INTx, enable Bus master.
|
// disable INTx, enable Bus master.
|
||||||
dev.set_command(dev.command() | Command::INTERRUPT_DISABLE | Command::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 {
|
for i in 0..table_size {
|
||||||
irq_allocate_handles.push(None);
|
irqs.push(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
@ -120,7 +120,7 @@ impl CapabilityMsixData {
|
|||||||
table_size: (dev.location().read16(cap_ptr + 2) & 0b11_1111_1111) + 1,
|
table_size: (dev.location().read16(cap_ptr + 2) & 0b11_1111_1111) + 1,
|
||||||
table_bar,
|
table_bar,
|
||||||
pending_table_bar: pba_bar,
|
pending_table_bar: pba_bar,
|
||||||
irqs: irq_allocate_handles,
|
irqs,
|
||||||
table_offset: table_offset,
|
table_offset: table_offset,
|
||||||
pending_table_offset: pba_offset,
|
pending_table_offset: pba_offset,
|
||||||
}
|
}
|
||||||
@ -131,7 +131,7 @@ impl CapabilityMsixData {
|
|||||||
(self.loc.read16(self.ptr + 2) & 0b11_1111_1111) + 1
|
(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 {
|
if index >= self.table_size {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -150,7 +150,7 @@ impl CapabilityMsixData {
|
|||||||
.unwrap();
|
.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()
|
self.irqs[index].as_mut()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,8 +38,8 @@ pub use self::cpu::CpuLocal;
|
|||||||
pub use self::error::Error;
|
pub use self::error::Error;
|
||||||
pub use self::prelude::Result;
|
pub use self::prelude::Result;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use arch::irq::{IrqCallbackHandle, IrqLine};
|
||||||
use core::{mem, panic::PanicInfo};
|
use core::{mem, panic::PanicInfo};
|
||||||
use trap::{IrqCallbackHandle, IrqLine};
|
|
||||||
use trapframe::TrapFrame;
|
use trapframe::TrapFrame;
|
||||||
|
|
||||||
static mut IRQ_CALLBACK_LIST: Vec<IrqCallbackHandle> = Vec::new();
|
static mut IRQ_CALLBACK_LIST: Vec<IrqCallbackHandle> = Vec::new();
|
||||||
|
@ -1,46 +1,46 @@
|
|||||||
use crate::arch::irq;
|
use crate::arch::irq::{self, IrqCallbackHandle, NOT_USING_IRQ};
|
||||||
use crate::arch::irq::{IRQ_LIST, NOT_USING_IRQ};
|
|
||||||
use crate::sync::{Mutex, MutexGuard};
|
|
||||||
use crate::task::{disable_preempt, DisablePreemptGuard};
|
use crate::task::{disable_preempt, DisablePreemptGuard};
|
||||||
use crate::util::recycle_allocator::RecycleAllocator;
|
|
||||||
use crate::{prelude::*, Error};
|
use crate::{prelude::*, Error};
|
||||||
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use trapframe::TrapFrame;
|
use trapframe::TrapFrame;
|
||||||
|
|
||||||
pub fn allocate_irq() -> Result<IrqAllocateHandle> {
|
/// An Interrupt ReQuest(IRQ) line. User can use `alloc` or `alloc_specific` to get specific IRQ line.
|
||||||
|
///
|
||||||
|
/// 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 IrqLine {
|
||||||
|
irq_num: u8,
|
||||||
|
irq: Arc<&'static irq::IrqLine>,
|
||||||
|
callbacks: Vec<IrqCallbackHandle>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrqLine {
|
||||||
|
pub fn alloc_specific(irq: u8) -> Result<Self> {
|
||||||
|
if NOT_USING_IRQ.lock().get_target(irq as usize) {
|
||||||
|
Ok(Self::new(irq))
|
||||||
|
} else {
|
||||||
|
Err(Error::NotEnoughResources)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alloc() -> Result<Self> {
|
||||||
let irq_num = NOT_USING_IRQ.lock().alloc();
|
let irq_num = NOT_USING_IRQ.lock().alloc();
|
||||||
if irq_num == usize::MAX {
|
if irq_num == usize::MAX {
|
||||||
Err(Error::NotEnoughResources)
|
Err(Error::NotEnoughResources)
|
||||||
} else {
|
} else {
|
||||||
Ok(IrqAllocateHandle::new(irq_num as u8))
|
Ok(Self::new(irq_num as u8))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn allocate_target_irq(target_irq: u8) -> Result<IrqAllocateHandle> {
|
|
||||||
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
|
|
||||||
///
|
|
||||||
/// When the handle is dropped, all the callback in this will be unregistered automatically.
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[must_use]
|
|
||||||
pub struct IrqAllocateHandle {
|
|
||||||
irq_num: u8,
|
|
||||||
irq: Arc<&'static IrqLine>,
|
|
||||||
callbacks: Vec<IrqCallbackHandle>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IrqAllocateHandle {
|
|
||||||
fn new(irq_num: u8) -> Self {
|
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 {
|
Self {
|
||||||
irq_num,
|
irq_num,
|
||||||
irq: unsafe { IrqLine::acquire(irq_num) },
|
irq: unsafe { irq::IrqLine::acquire(irq_num) },
|
||||||
callbacks: Vec::new(),
|
callbacks: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ impl IrqAllocateHandle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for IrqAllocateHandle {
|
impl Clone for IrqLine {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
irq_num: self.irq_num.clone(),
|
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) {
|
fn drop(&mut self) {
|
||||||
if Arc::strong_count(&self.irq) == 1 {
|
if Arc::strong_count(&self.irq) == 1 {
|
||||||
NOT_USING_IRQ.lock().dealloc(self.irq_num as usize);
|
NOT_USING_IRQ.lock().dealloc(self.irq_num as usize);
|
||||||
@ -83,101 +83,6 @@ impl Drop for IrqAllocateHandle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ID_ALLOCATOR: Mutex<RecycleAllocator> = Mutex::new(RecycleAllocator::new());
|
|
||||||
|
|
||||||
pub struct CallbackElement {
|
|
||||||
function: Box<dyn Fn(&TrapFrame) + Send + Sync + 'static>,
|
|
||||||
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<Vec<CallbackElement>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
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<CallbackElement>> {
|
|
||||||
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<F>(&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<dyn Fn(&IrqLine)+Sync+Send+'static>>
|
|
||||||
}
|
|
||||||
|
|
||||||
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).
|
/// Disable all IRQs on the current CPU (i.e., locally).
|
||||||
///
|
///
|
||||||
/// This function returns a guard object, which will automatically enable local IRQs again when
|
/// This function returns a guard object, which will automatically enable local IRQs again when
|
||||||
|
@ -2,8 +2,7 @@ mod handler;
|
|||||||
mod irq;
|
mod irq;
|
||||||
|
|
||||||
pub(crate) use self::handler::call_irq_callback_functions;
|
pub(crate) use self::handler::call_irq_callback_functions;
|
||||||
pub use self::irq::{allocate_irq, disable_local, DisabledLocalIrqGuard, IrqAllocateHandle};
|
pub use self::irq::{disable_local, DisabledLocalIrqGuard, IrqLine};
|
||||||
pub(crate) use self::irq::{allocate_target_irq, IrqCallbackHandle, IrqLine};
|
|
||||||
pub use trapframe::TrapFrame;
|
pub use trapframe::TrapFrame;
|
||||||
|
|
||||||
pub(crate) fn init() {
|
pub(crate) fn init() {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use alloc::vec::Vec;
|
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 {
|
pub struct VirtioMsixManager {
|
||||||
config_msix_vector: u16,
|
config_msix_vector: u16,
|
||||||
@ -17,8 +17,8 @@ impl VirtioMsixManager {
|
|||||||
pub fn new(mut msix: CapabilityMsixData) -> Self {
|
pub fn new(mut msix: CapabilityMsixData) -> Self {
|
||||||
let mut msix_vector_list: Vec<u16> = (0..msix.table_size()).collect();
|
let mut msix_vector_list: Vec<u16> = (0..msix.table_size()).collect();
|
||||||
for i in msix_vector_list.iter() {
|
for i in msix_vector_list.iter() {
|
||||||
let allocate_handle = jinux_frame::trap::allocate_irq().unwrap();
|
let irq = jinux_frame::trap::IrqLine::alloc().unwrap();
|
||||||
msix.set_interrupt_vector(allocate_handle, *i);
|
msix.set_interrupt_vector(irq, *i);
|
||||||
}
|
}
|
||||||
let config_msix_vector = msix_vector_list.pop().unwrap();
|
let config_msix_vector = msix_vector_list.pop().unwrap();
|
||||||
let shared_interrupt_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.
|
/// 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.config_msix_vector,
|
||||||
self.msix.irq_mut(self.config_msix_vector as usize).unwrap(),
|
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.
|
/// Get shared interrupt IRQ used by virtqueue. If a virtqueue will not send interrupt frequently.
|
||||||
/// Then this virtqueue should use shared interrupt IRQ.
|
/// Then this virtqueue should use shared interrupt IRQ.
|
||||||
/// This function will return the MSI-X vector and corresponding 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.shared_interrupt_vector,
|
||||||
self.msix
|
self.msix
|
||||||
@ -54,7 +54,7 @@ impl VirtioMsixManager {
|
|||||||
/// Pop unused vector. If a virtqueue will send interrupt frequently.
|
/// Pop unused vector. If a virtqueue will send interrupt frequently.
|
||||||
/// Then this virtqueue should use the single IRQ that this function provides.
|
/// Then this virtqueue should use the single IRQ that this function provides.
|
||||||
/// this function will return the MSI-X vector and corresponding IRQ.
|
/// 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()?;
|
let vector = self.unused_msix_vectors.pop()?;
|
||||||
self.used_msix_vectors.push(vector);
|
self.used_msix_vectors.push(vector);
|
||||||
Some((vector, self.msix.irq_mut(vector as usize).unwrap()))
|
Some((vector, self.msix.irq_mut(vector as usize).unwrap()))
|
||||||
|
Reference in New Issue
Block a user