mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-09 11:16:47 +00:00
feat:(riscv/intr) 实现riscv plic驱动,能处理外部中断 (#799)
* feat:(riscv/intr) 实现riscv plic驱动,能处理外部中断 - 实现riscv plic驱动,能处理外部中断 - 能收到virtio-blk的中断 - 实现fasteoi interrupt handler
This commit is contained in:
parent
17dc558977
commit
0102d69fdd
@ -47,8 +47,8 @@ num-traits = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/num
|
|||||||
smoltcp = { version = "=0.11.0", default-features = false, features = ["log", "alloc", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "socket-dhcpv4", "socket-dns", "proto-ipv4", "proto-ipv6"]}
|
smoltcp = { version = "=0.11.0", default-features = false, features = ["log", "alloc", "socket-raw", "socket-udp", "socket-tcp", "socket-icmp", "socket-dhcpv4", "socket-dns", "proto-ipv4", "proto-ipv6"]}
|
||||||
system_error = { path = "crates/system_error" }
|
system_error = { path = "crates/system_error" }
|
||||||
unified-init = { path = "crates/unified-init" }
|
unified-init = { path = "crates/unified-init" }
|
||||||
virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers", rev = "448a781" }
|
virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers", rev = "f91c807965" }
|
||||||
fdt = "=0.1.5"
|
fdt = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/fdt", rev = "9862813020" }
|
||||||
uefi = { version = "=0.26.0", features = ["alloc"] }
|
uefi = { version = "=0.26.0", features = ["alloc"] }
|
||||||
uefi-raw = "=0.5.0"
|
uefi-raw = "=0.5.0"
|
||||||
paste = "=1.0.14"
|
paste = "=1.0.14"
|
||||||
|
@ -20,6 +20,12 @@ impl AllocBitmap {
|
|||||||
core: BitMapCore::new(),
|
core: BitMapCore::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bitand_assign(&mut self, rhs: &Self) {
|
||||||
|
for i in 0..rhs.data.len() {
|
||||||
|
self.data[i] &= rhs.data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitMapOps<usize> for AllocBitmap {
|
impl BitMapOps<usize> for AllocBitmap {
|
||||||
@ -111,8 +117,8 @@ impl BitMapOps<usize> for AllocBitmap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitAnd for AllocBitmap {
|
impl BitAnd for &AllocBitmap {
|
||||||
type Output = Self;
|
type Output = AllocBitmap;
|
||||||
|
|
||||||
fn bitand(self, rhs: Self) -> Self::Output {
|
fn bitand(self, rhs: Self) -> Self::Output {
|
||||||
let mut result = AllocBitmap::new(self.elements);
|
let mut result = AllocBitmap::new(self.elements);
|
||||||
@ -122,3 +128,11 @@ impl BitAnd for AllocBitmap {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl BitAnd for AllocBitmap {
|
||||||
|
type Output = AllocBitmap;
|
||||||
|
|
||||||
|
fn bitand(self, rhs: Self) -> Self::Output {
|
||||||
|
&self & &rhs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -663,3 +663,23 @@ fn test_alloc_bitmap_bitand_128() {
|
|||||||
assert_eq!(bitmap3.first_false_index(), Some(2));
|
assert_eq!(bitmap3.first_false_index(), Some(2));
|
||||||
assert_eq!(bitmap3.last_index(), Some(67));
|
assert_eq!(bitmap3.last_index(), Some(67));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_alloc_bitmap_bitand_assign_128() {
|
||||||
|
let mut bitmap = AllocBitmap::new(128);
|
||||||
|
bitmap.set_all(true);
|
||||||
|
|
||||||
|
let mut bitmap2 = AllocBitmap::new(128);
|
||||||
|
|
||||||
|
bitmap2.set(0, true);
|
||||||
|
bitmap2.set(1, true);
|
||||||
|
bitmap2.set(67, true);
|
||||||
|
|
||||||
|
bitmap.bitand_assign(&bitmap2);
|
||||||
|
|
||||||
|
assert_eq!(bitmap.len(), 128);
|
||||||
|
assert_eq!(bitmap.size(), 16);
|
||||||
|
assert_eq!(bitmap.first_index(), Some(0));
|
||||||
|
assert_eq!(bitmap.first_false_index(), Some(2));
|
||||||
|
assert_eq!(bitmap.last_index(), Some(67));
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
/// @param x 目标u64
|
/// @param x 目标u64
|
||||||
/// @return i32 bit-number(0..63) of the first (least significant) zero bit.
|
/// @return i32 bit-number(0..63) of the first (least significant) zero bit.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn ffz(x: u64) -> i32 {
|
pub fn ffz(x: u64) -> i32 {
|
||||||
(!x).trailing_zeros() as i32
|
(!x).trailing_zeros() as i32
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ use system_error::SystemError;
|
|||||||
use crate::{
|
use crate::{
|
||||||
driver::open_firmware::fdt::OpenFirmwareFdtDriver,
|
driver::open_firmware::fdt::OpenFirmwareFdtDriver,
|
||||||
init::boot_params,
|
init::boot_params,
|
||||||
kdebug,
|
|
||||||
libs::align::page_align_up,
|
libs::align::page_align_up,
|
||||||
mm::{mmio_buddy::mmio_pool, MemoryManagementArch, PhysAddr},
|
mm::{mmio_buddy::mmio_pool, MemoryManagementArch, PhysAddr},
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
use crate::arch::{
|
use crate::arch::{
|
||||||
asm::csr::{
|
asm::csr::{CSR_SCAUSE, CSR_SEPC, CSR_SSCRATCH, CSR_SSTATUS, CSR_STVAL, SR_SPP},
|
||||||
CSR_SCAUSE, CSR_SEPC, CSR_SSCRATCH, CSR_SSTATUS, CSR_STVAL, SR_FS_VS, SR_SPP, SR_SUM,
|
|
||||||
},
|
|
||||||
cpu::LocalContext,
|
cpu::LocalContext,
|
||||||
interrupt::TrapFrame,
|
interrupt::TrapFrame,
|
||||||
};
|
};
|
||||||
|
@ -5,9 +5,7 @@ use core::hint::spin_loop;
|
|||||||
|
|
||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::{
|
use crate::{arch::syscall::syscall_handler, driver::irqchip::riscv_intc::riscv_intc_irq, kerror};
|
||||||
arch::syscall::syscall_handler, driver::irqchip::riscv_intc::riscv_intc_irq, kdebug, kerror,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::TrapFrame;
|
use super::TrapFrame;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ use riscv::register::{scause::Scause, sstatus::Sstatus};
|
|||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::irqchip::riscv_intc::riscv_intc_init,
|
driver::irqchip::{riscv_intc::riscv_intc_init, riscv_sifive_plic::riscv_sifive_plic_init},
|
||||||
exception::{InterruptArch, IrqFlags, IrqFlagsGuard, IrqNumber},
|
exception::{InterruptArch, IrqFlags, IrqFlagsGuard, IrqNumber},
|
||||||
libs::align::align_up,
|
libs::align::align_up,
|
||||||
};
|
};
|
||||||
@ -17,6 +17,9 @@ pub struct RiscV64InterruptArch;
|
|||||||
|
|
||||||
impl InterruptArch for RiscV64InterruptArch {
|
impl InterruptArch for RiscV64InterruptArch {
|
||||||
unsafe fn arch_irq_init() -> Result<(), SystemError> {
|
unsafe fn arch_irq_init() -> Result<(), SystemError> {
|
||||||
|
Self::interrupt_disable();
|
||||||
|
riscv_sifive_plic_init()?;
|
||||||
|
// 注意,intc的初始化必须在plic之后,不然会导致plic无法关联上中断
|
||||||
riscv_intc_init()?;
|
riscv_intc_init()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -43,6 +43,7 @@ pub struct RiscV64MMArch;
|
|||||||
|
|
||||||
impl RiscV64MMArch {
|
impl RiscV64MMArch {
|
||||||
/// 使远程cpu的TLB中,指定地址范围的页失效
|
/// 使远程cpu的TLB中,指定地址范围的页失效
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn remote_invalidate_page(
|
pub fn remote_invalidate_page(
|
||||||
cpu: ProcessorId,
|
cpu: ProcessorId,
|
||||||
address: VirtAddr,
|
address: VirtAddr,
|
||||||
@ -57,6 +58,7 @@ impl RiscV64MMArch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// 使指定远程cpu的TLB中,所有范围的页失效
|
/// 使指定远程cpu的TLB中,所有范围的页失效
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn remote_invalidate_all(cpu: ProcessorId) -> Result<(), SbiRet> {
|
pub fn remote_invalidate_all(cpu: ProcessorId) -> Result<(), SbiRet> {
|
||||||
let r = Self::remote_invalidate_page(
|
let r = Self::remote_invalidate_page(
|
||||||
cpu,
|
cpu,
|
||||||
|
@ -227,16 +227,23 @@ pub fn x86_vector_domain() -> &'static Arc<IrqDomain> {
|
|||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn arch_early_irq_init() -> Result<(), SystemError> {
|
pub fn arch_early_irq_init() -> Result<(), SystemError> {
|
||||||
|
const IRQ_SIZE: u32 = 223;
|
||||||
let vec_domain = irq_domain_manager()
|
let vec_domain = irq_domain_manager()
|
||||||
.create_and_add(
|
.create_and_add(
|
||||||
"VECTOR".to_string(),
|
"VECTOR".to_string(),
|
||||||
&X86VectorDomainOps,
|
&X86VectorDomainOps,
|
||||||
IrqNumber::new(32),
|
IrqNumber::new(32),
|
||||||
HardwareIrqNumber::new(32),
|
HardwareIrqNumber::new(32),
|
||||||
223,
|
IRQ_SIZE,
|
||||||
)
|
)
|
||||||
.ok_or(SystemError::ENOMEM)?;
|
.ok_or(SystemError::ENOMEM)?;
|
||||||
irq_domain_manager().set_default_domain(vec_domain.clone());
|
irq_domain_manager().set_default_domain(vec_domain.clone());
|
||||||
|
irq_domain_manager().domain_associate_many(
|
||||||
|
&vec_domain,
|
||||||
|
IrqNumber::new(0),
|
||||||
|
HardwareIrqNumber::new(0),
|
||||||
|
IRQ_SIZE,
|
||||||
|
);
|
||||||
unsafe { X86_VECTOR_DOMAIN = Some(vec_domain) };
|
unsafe { X86_VECTOR_DOMAIN = Some(vec_domain) };
|
||||||
|
|
||||||
let apic_chip = Arc::new(LocalApicChip::new());
|
let apic_chip = Arc::new(LocalApicChip::new());
|
||||||
|
@ -32,6 +32,7 @@ use crate::{
|
|||||||
VirtIODevice, VirtIODeviceIndex, VirtIODriver, VIRTIO_VENDOR_ID,
|
VirtIODevice, VirtIODeviceIndex, VirtIODriver, VIRTIO_VENDOR_ID,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
exception::{irqdesc::IrqReturn, IrqNumber},
|
||||||
filesystem::{kernfs::KernFSInode, mbr::MbrDiskPartionTable},
|
filesystem::{kernfs::KernFSInode, mbr::MbrDiskPartionTable},
|
||||||
init::initcall::INITCALL_POSTCORE,
|
init::initcall::INITCALL_POSTCORE,
|
||||||
libs::{
|
libs::{
|
||||||
@ -85,15 +86,15 @@ unsafe impl Sync for VirtIOBlkDevice {}
|
|||||||
|
|
||||||
impl VirtIOBlkDevice {
|
impl VirtIOBlkDevice {
|
||||||
pub fn new(transport: VirtIOTransport, dev_id: Arc<DeviceId>) -> Option<Arc<Self>> {
|
pub fn new(transport: VirtIOTransport, dev_id: Arc<DeviceId>) -> Option<Arc<Self>> {
|
||||||
|
let irq = transport.irq().map(|irq| IrqNumber::new(irq.data()));
|
||||||
let device_inner = VirtIOBlk::<HalImpl, VirtIOTransport>::new(transport);
|
let device_inner = VirtIOBlk::<HalImpl, VirtIOTransport>::new(transport);
|
||||||
if let Err(e) = device_inner {
|
if let Err(e) = device_inner {
|
||||||
kerror!("VirtIOBlkDevice '{dev_id:?}' create failed: {:?}", e);
|
kerror!("VirtIOBlkDevice '{dev_id:?}' create failed: {:?}", e);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
// !!!! 在这里临时测试virtio-blk的读写功能,后续需要删除 !!!!
|
|
||||||
// 目前read会报错 `NotReady`
|
|
||||||
let device_inner: VirtIOBlk<HalImpl, VirtIOTransport> = device_inner.unwrap();
|
|
||||||
|
|
||||||
|
let mut device_inner: VirtIOBlk<HalImpl, VirtIOTransport> = device_inner.unwrap();
|
||||||
|
device_inner.enable_interrupts();
|
||||||
let dev = Arc::new_cyclic(|self_ref| Self {
|
let dev = Arc::new_cyclic(|self_ref| Self {
|
||||||
self_ref: self_ref.clone(),
|
self_ref: self_ref.clone(),
|
||||||
dev_id,
|
dev_id,
|
||||||
@ -104,6 +105,7 @@ impl VirtIOBlkDevice {
|
|||||||
virtio_index: None,
|
virtio_index: None,
|
||||||
device_common: DeviceCommonData::default(),
|
device_common: DeviceCommonData::default(),
|
||||||
kobject_common: KObjectCommonData::default(),
|
kobject_common: KObjectCommonData::default(),
|
||||||
|
irq,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -190,6 +192,7 @@ struct InnerVirtIOBlkDevice {
|
|||||||
virtio_index: Option<VirtIODeviceIndex>,
|
virtio_index: Option<VirtIODeviceIndex>,
|
||||||
device_common: DeviceCommonData,
|
device_common: DeviceCommonData,
|
||||||
kobject_common: KObjectCommonData,
|
kobject_common: KObjectCommonData,
|
||||||
|
irq: Option<IrqNumber>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for InnerVirtIOBlkDevice {
|
impl Debug for InnerVirtIOBlkDevice {
|
||||||
@ -199,11 +202,16 @@ impl Debug for InnerVirtIOBlkDevice {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl VirtIODevice for VirtIOBlkDevice {
|
impl VirtIODevice for VirtIOBlkDevice {
|
||||||
|
fn irq(&self) -> Option<IrqNumber> {
|
||||||
|
self.inner().irq
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_irq(
|
fn handle_irq(
|
||||||
&self,
|
&self,
|
||||||
_irq: crate::exception::IrqNumber,
|
_irq: crate::exception::IrqNumber,
|
||||||
) -> Result<crate::exception::irqdesc::IrqReturn, system_error::SystemError> {
|
) -> Result<IrqReturn, system_error::SystemError> {
|
||||||
todo!("VirtIOBlkDevice::handle_irq")
|
// todo: handle virtio blk irq
|
||||||
|
Ok(crate::exception::irqdesc::IrqReturn::Handled)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dev_id(&self) -> &Arc<DeviceId> {
|
fn dev_id(&self) -> &Arc<DeviceId> {
|
||||||
|
@ -6,14 +6,17 @@ use system_error::SystemError;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{interrupt::TrapFrame, time::riscv_time_base_freq, CurrentIrqArch, CurrentTimeArch},
|
arch::{interrupt::TrapFrame, time::riscv_time_base_freq, CurrentIrqArch, CurrentTimeArch},
|
||||||
driver::base::device::DeviceId,
|
driver::{
|
||||||
|
base::device::DeviceId,
|
||||||
|
irqchip::riscv_intc::{riscv_intc_assicate_irq, riscv_intc_hwirq_to_virq},
|
||||||
|
},
|
||||||
exception::{
|
exception::{
|
||||||
irqdata::{IrqHandlerData, IrqLineStatus},
|
irqdata::{IrqHandlerData, IrqLineStatus},
|
||||||
irqdesc::{
|
irqdesc::{
|
||||||
irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandleFlags, IrqHandler, IrqReturn,
|
irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandleFlags, IrqHandler, IrqReturn,
|
||||||
},
|
},
|
||||||
manage::irq_manager,
|
manage::irq_manager,
|
||||||
InterruptArch, IrqNumber,
|
HardwareIrqNumber, InterruptArch, IrqNumber,
|
||||||
},
|
},
|
||||||
libs::spinlock::SpinLock,
|
libs::spinlock::SpinLock,
|
||||||
mm::percpu::PerCpu,
|
mm::percpu::PerCpu,
|
||||||
@ -42,7 +45,7 @@ static mut HART0_NSEC_PASSED: usize = 0;
|
|||||||
static mut HART0_LAST_UPDATED: u64 = 0;
|
static mut HART0_LAST_UPDATED: u64 = 0;
|
||||||
|
|
||||||
impl RiscVSbiTimer {
|
impl RiscVSbiTimer {
|
||||||
pub const TIMER_IRQ: IrqNumber = IrqNumber::from(5);
|
pub const TIMER_IRQ: HardwareIrqNumber = HardwareIrqNumber::new(5);
|
||||||
|
|
||||||
fn handle_irq(trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
|
fn handle_irq(trap_frame: &mut TrapFrame) -> Result<(), SystemError> {
|
||||||
// 更新下一次中断时间
|
// 更新下一次中断时间
|
||||||
@ -117,7 +120,7 @@ pub fn riscv_sbi_timer_init_local() {
|
|||||||
|
|
||||||
irq_manager()
|
irq_manager()
|
||||||
.request_irq(
|
.request_irq(
|
||||||
RiscVSbiTimer::TIMER_IRQ,
|
riscv_intc_hwirq_to_virq(RiscVSbiTimer::TIMER_IRQ).unwrap(),
|
||||||
"riscv_clocksource".to_string(),
|
"riscv_clocksource".to_string(),
|
||||||
&RiscvSbiTimerHandler,
|
&RiscvSbiTimerHandler,
|
||||||
IrqHandleFlags::IRQF_SHARED | IrqHandleFlags::IRQF_PERCPU,
|
IrqHandleFlags::IRQF_SHARED | IrqHandleFlags::IRQF_PERCPU,
|
||||||
@ -136,7 +139,8 @@ pub fn riscv_sbi_timer_init_local() {
|
|||||||
|
|
||||||
#[inline(never)]
|
#[inline(never)]
|
||||||
pub fn riscv_sbi_timer_irq_desc_init() {
|
pub fn riscv_sbi_timer_irq_desc_init() {
|
||||||
let desc = irq_desc_manager().lookup(RiscVSbiTimer::TIMER_IRQ).unwrap();
|
let virq = riscv_intc_assicate_irq(RiscVSbiTimer::TIMER_IRQ).unwrap();
|
||||||
|
let desc = irq_desc_manager().lookup(virq).unwrap();
|
||||||
|
|
||||||
desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
|
desc.modify_status(IrqLineStatus::IRQ_LEVEL, IrqLineStatus::empty());
|
||||||
desc.set_handler(&RiscvSbiTimerIrqFlowHandler);
|
desc.set_handler(&RiscvSbiTimerIrqFlowHandler);
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
#[cfg(target_arch = "riscv64")]
|
#[cfg(target_arch = "riscv64")]
|
||||||
pub mod riscv_intc;
|
pub mod riscv_intc;
|
||||||
|
#[cfg(target_arch = "riscv64")]
|
||||||
|
pub mod riscv_sifive_plic;
|
||||||
|
@ -17,6 +17,8 @@ use crate::{
|
|||||||
sched::{SchedMode, __schedule},
|
sched::{SchedMode, __schedule},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::riscv_sifive_plic::do_plic_irq;
|
||||||
|
|
||||||
static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None;
|
static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = None;
|
||||||
static mut RISCV_INTC_CHIP: Option<Arc<RiscvIntcChip>> = None;
|
static mut RISCV_INTC_CHIP: Option<Arc<RiscvIntcChip>> = None;
|
||||||
|
|
||||||
@ -30,6 +32,9 @@ fn riscv_intc_chip() -> Option<&'static Arc<RiscvIntcChip>> {
|
|||||||
unsafe { RISCV_INTC_CHIP.as_ref() }
|
unsafe { RISCV_INTC_CHIP.as_ref() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// RISC-V INTC虚拟中断号的起始值(192映射物理的0)
|
||||||
|
pub const RISCV_INTC_VIRQ_START: u32 = 192;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct RiscvIntcChip {
|
struct RiscvIntcChip {
|
||||||
inner: SpinLock<InnerIrqChip>,
|
inner: SpinLock<InnerIrqChip>,
|
||||||
@ -87,6 +92,7 @@ impl IrqChip for RiscvIntcChip {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RiscvIntcChip {
|
impl RiscvIntcChip {
|
||||||
|
const IRQ_SIZE: u32 = 64;
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: SpinLock::new(InnerIrqChip {
|
inner: SpinLock::new(InnerIrqChip {
|
||||||
@ -143,7 +149,11 @@ pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let intc_domain = irq_domain_manager()
|
let intc_domain = irq_domain_manager()
|
||||||
.create_and_add_linear("riscv-intc".to_string(), &RiscvIntcDomainOps, 64)
|
.create_and_add_linear(
|
||||||
|
"riscv-intc".to_string(),
|
||||||
|
&RiscvIntcDomainOps,
|
||||||
|
RiscvIntcChip::IRQ_SIZE,
|
||||||
|
)
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
kerror!("Failed to create riscv-intc domain");
|
kerror!("Failed to create riscv-intc domain");
|
||||||
SystemError::ENXIO
|
SystemError::ENXIO
|
||||||
@ -152,7 +162,7 @@ pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
|
|||||||
irq_domain_manager().set_default_domain(intc_domain.clone());
|
irq_domain_manager().set_default_domain(intc_domain.clone());
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
RISCV_INTC_DOMAIN = Some(intc_domain);
|
RISCV_INTC_DOMAIN = Some(intc_domain.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
riscv_sbi_timer_irq_desc_init();
|
riscv_sbi_timer_irq_desc_init();
|
||||||
@ -160,12 +170,58 @@ pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 把硬件中断号转换为riscv intc芯片的中断域的虚拟中断号
|
||||||
|
pub const fn riscv_intc_hwirq_to_virq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> {
|
||||||
|
if hwirq.data() < RiscvIntcChip::IRQ_SIZE {
|
||||||
|
Some(IrqNumber::new(hwirq.data() + RISCV_INTC_VIRQ_START))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 把riscv intc芯片的的中断域的虚拟中断号转换为硬件中断号
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub const fn riscv_intc_virq_to_hwirq(virq: IrqNumber) -> Option<HardwareIrqNumber> {
|
||||||
|
if virq.data() >= RISCV_INTC_VIRQ_START
|
||||||
|
&& virq.data() < RISCV_INTC_VIRQ_START + RiscvIntcChip::IRQ_SIZE
|
||||||
|
{
|
||||||
|
Some(HardwareIrqNumber::new(virq.data() - RISCV_INTC_VIRQ_START))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 将硬件中断号与riscv intc芯片的虚拟中断号关联
|
||||||
|
pub fn riscv_intc_assicate_irq(hwirq: HardwareIrqNumber) -> Option<IrqNumber> {
|
||||||
|
let virq = riscv_intc_hwirq_to_virq(hwirq)?;
|
||||||
|
irq_domain_manager()
|
||||||
|
.domain_associate(
|
||||||
|
riscv_intc_domain().as_ref().or_else(|| {
|
||||||
|
kerror!("riscv_intc_domain is None");
|
||||||
|
None
|
||||||
|
})?,
|
||||||
|
virq,
|
||||||
|
hwirq,
|
||||||
|
)
|
||||||
|
.ok();
|
||||||
|
|
||||||
|
Some(virq)
|
||||||
|
}
|
||||||
|
|
||||||
/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-riscv-intc.c#23
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-riscv-intc.c#23
|
||||||
pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
|
pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
|
||||||
let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32);
|
let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32);
|
||||||
// kdebug!("riscv64_do_irq: interrupt {hwirq:?}");
|
if hwirq.data() == 9 {
|
||||||
GenericIrqHandler::handle_domain_irq(riscv_intc_domain().clone().unwrap(), hwirq, trap_frame)
|
// external interrupt
|
||||||
|
do_plic_irq(trap_frame);
|
||||||
|
} else {
|
||||||
|
GenericIrqHandler::handle_domain_irq(
|
||||||
|
riscv_intc_domain().clone().unwrap(),
|
||||||
|
hwirq,
|
||||||
|
trap_frame,
|
||||||
|
)
|
||||||
.ok();
|
.ok();
|
||||||
|
}
|
||||||
do_softirq();
|
do_softirq();
|
||||||
if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {
|
if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {
|
||||||
__schedule(SchedMode::SM_PREEMPT);
|
__schedule(SchedMode::SM_PREEMPT);
|
||||||
|
658
kernel/src/driver/irqchip/riscv_sifive_plic.rs
Normal file
658
kernel/src/driver/irqchip/riscv_sifive_plic.rs
Normal file
@ -0,0 +1,658 @@
|
|||||||
|
//! 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//! This driver implements a version of the RISC-V PLIC with the actual layout
|
||||||
|
//! specified in chapter 8 of the SiFive U5 Coreplex Series Manual:
|
||||||
|
//!
|
||||||
|
//! https://static.dev.sifive.com/U54-MC-RVCoreIP.pdf
|
||||||
|
//!
|
||||||
|
//! The largest number supported by devices marked as 'sifive,plic-1.0.0', is
|
||||||
|
//! 1024, of which device 0 is defined as non-existent by the RISC-V Privileged
|
||||||
|
//! Spec.
|
||||||
|
//!
|
||||||
|
|
||||||
|
use core::{
|
||||||
|
fmt::Debug,
|
||||||
|
ops::Deref,
|
||||||
|
ptr::{read_volatile, write_volatile},
|
||||||
|
sync::atomic::AtomicBool,
|
||||||
|
};
|
||||||
|
|
||||||
|
use alloc::{
|
||||||
|
string::ToString,
|
||||||
|
sync::{Arc, Weak},
|
||||||
|
};
|
||||||
|
use bitmap::AllocBitmap;
|
||||||
|
use fdt::node::FdtNode;
|
||||||
|
use system_error::SystemError;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
arch::interrupt::TrapFrame,
|
||||||
|
driver::open_firmware::fdt::open_firmware_fdt_driver,
|
||||||
|
exception::{
|
||||||
|
handle::fast_eoi_irq_handler,
|
||||||
|
irqchip::{IrqChip, IrqChipData, IrqChipFlags, IrqChipSetMaskResult},
|
||||||
|
irqdata::IrqData,
|
||||||
|
irqdesc::{irq_desc_manager, GenericIrqHandler},
|
||||||
|
irqdomain::{irq_domain_manager, IrqDomain, IrqDomainOps},
|
||||||
|
manage::irq_manager,
|
||||||
|
HardwareIrqNumber, IrqNumber,
|
||||||
|
},
|
||||||
|
libs::{
|
||||||
|
cpumask::CpuMask,
|
||||||
|
once::Once,
|
||||||
|
spinlock::{SpinLock, SpinLockGuard},
|
||||||
|
},
|
||||||
|
mm::{
|
||||||
|
mmio_buddy::{mmio_pool, MMIOSpaceGuard},
|
||||||
|
percpu::{PerCpu, PerCpuVar},
|
||||||
|
PhysAddr, VirtAddr,
|
||||||
|
},
|
||||||
|
smp::cpu::{smp_cpu_manager, ProcessorId},
|
||||||
|
};
|
||||||
|
|
||||||
|
static mut PLIC_HANDLERS: Option<PerCpuVar<PlicHandler>> = None;
|
||||||
|
|
||||||
|
static mut PLIC_IRQ_CHIP: Option<Arc<PlicIrqChip>> = None;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn plic_irq_chip() -> Arc<PlicIrqChip> {
|
||||||
|
unsafe { PLIC_IRQ_CHIP.as_ref().unwrap().clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn plic_handlers() -> &'static PerCpuVar<PlicHandler> {
|
||||||
|
unsafe { PLIC_HANDLERS.as_ref().unwrap() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
struct PlicChipData {
|
||||||
|
irq_domain: Weak<IrqDomain>,
|
||||||
|
phandle: u32,
|
||||||
|
lmask: SpinLock<CpuMask>,
|
||||||
|
mmio_guard: Option<MMIOSpaceGuard>,
|
||||||
|
regs: VirtAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlicChipData {
|
||||||
|
fn new(
|
||||||
|
irq_domain: Weak<IrqDomain>,
|
||||||
|
mmio_guard: MMIOSpaceGuard,
|
||||||
|
regs: VirtAddr,
|
||||||
|
phandle: u32,
|
||||||
|
) -> Arc<Self> {
|
||||||
|
let r = Self {
|
||||||
|
irq_domain,
|
||||||
|
lmask: SpinLock::new(CpuMask::new()),
|
||||||
|
mmio_guard: Some(mmio_guard),
|
||||||
|
regs,
|
||||||
|
phandle,
|
||||||
|
};
|
||||||
|
|
||||||
|
Arc::new(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lmask(&self) -> SpinLockGuard<CpuMask> {
|
||||||
|
self.lmask.lock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for PlicChipData {
|
||||||
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
|
f.debug_struct("PlicChipData").finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrqChipData for PlicChipData {
|
||||||
|
fn as_any_ref(&self) -> &dyn core::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PlicHandler {
|
||||||
|
priv_data: Option<Arc<PlicChipData>>,
|
||||||
|
present: AtomicBool,
|
||||||
|
inner: SpinLock<InnerPlicHandler>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InnerPlicHandler {
|
||||||
|
hart_base: VirtAddr,
|
||||||
|
enable_base: VirtAddr,
|
||||||
|
enable_save: Option<AllocBitmap>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlicHandler {
|
||||||
|
fn new() -> Self {
|
||||||
|
let inner = InnerPlicHandler {
|
||||||
|
hart_base: VirtAddr::new(0),
|
||||||
|
enable_base: VirtAddr::new(0),
|
||||||
|
enable_save: None,
|
||||||
|
};
|
||||||
|
Self {
|
||||||
|
priv_data: None,
|
||||||
|
present: AtomicBool::new(false),
|
||||||
|
inner: SpinLock::new(inner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_threshold(&self, threshold: u32) {
|
||||||
|
let inner = self.inner();
|
||||||
|
unsafe {
|
||||||
|
/* priority must be > threshold to trigger an interrupt */
|
||||||
|
core::ptr::write_volatile(
|
||||||
|
(inner.hart_base + PlicIrqChip::CONTEXT_THRESHOLD).data() as *mut u32,
|
||||||
|
threshold,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn force_set_priv_data(&mut self, priv_data: Arc<PlicChipData>) {
|
||||||
|
self.priv_data = Some(priv_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn priv_data(&self) -> Option<Arc<PlicChipData>> {
|
||||||
|
self.priv_data.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn present(&self) -> bool {
|
||||||
|
self.present.load(core::sync::atomic::Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_present(&self, present: bool) {
|
||||||
|
self.present
|
||||||
|
.store(present, core::sync::atomic::Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inner(&self) -> SpinLockGuard<InnerPlicHandler> {
|
||||||
|
self.inner.lock()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle(&self, hwirq: HardwareIrqNumber, enable: bool) {
|
||||||
|
let inner = self.inner();
|
||||||
|
let reg = (inner.enable_base + ((hwirq.data() / 32) * 4) as usize).data() as *mut u32;
|
||||||
|
let hwirq_mask = 1 << (hwirq.data() % 32);
|
||||||
|
|
||||||
|
if enable {
|
||||||
|
unsafe {
|
||||||
|
core::ptr::write_volatile(reg, core::ptr::read_volatile(reg) | hwirq_mask);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
core::ptr::write_volatile(reg, core::ptr::read_volatile(reg) & !hwirq_mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn plic_irq_toggle(cpumask: &CpuMask, irq_data: &Arc<IrqData>, enable: bool) {
|
||||||
|
cpumask.iter_cpu().for_each(|cpu| {
|
||||||
|
kdebug!("plic: irq_toggle: cpu: {cpu:?}");
|
||||||
|
let handler = unsafe { plic_handlers().force_get(cpu) };
|
||||||
|
handler.toggle(irq_data.hardware_irq(), enable);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SiFive PLIC中断控制器
|
||||||
|
///
|
||||||
|
/// https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c#204
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct PlicIrqChip;
|
||||||
|
#[allow(dead_code)]
|
||||||
|
impl PlicIrqChip {
|
||||||
|
const COMPATIBLE: &'static str = "sifive,plic-1.0.0";
|
||||||
|
|
||||||
|
const MAX_DEVICES: u32 = 1024;
|
||||||
|
const MAX_CONTEXTS: u32 = 15872;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each interrupt source has a priority register associated with it.
|
||||||
|
* We always hardwire it to one in Linux.
|
||||||
|
*/
|
||||||
|
const PRIORITY_BASE: usize = 0;
|
||||||
|
const PRIORITY_PER_ID: usize = 4;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each hart context has a vector of interrupt enable bits associated with it.
|
||||||
|
* There's one bit for each interrupt source.
|
||||||
|
*/
|
||||||
|
const CONTEXT_ENABLE_BASE: usize = 0x2080;
|
||||||
|
const CONTEXT_ENABLE_SIZE: usize = 0x100;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each hart context has a set of control registers associated with it. Right
|
||||||
|
* now there's only two: a source priority threshold over which the hart will
|
||||||
|
* take an interrupt, and a register to claim interrupts.
|
||||||
|
*/
|
||||||
|
const CONTEXT_BASE: usize = 0x201000;
|
||||||
|
const CONTEXT_SIZE: usize = 0x2000;
|
||||||
|
const CONTEXT_THRESHOLD: usize = 0x00;
|
||||||
|
const CONTEXT_CLAIM: usize = 0x04;
|
||||||
|
|
||||||
|
const PLIC_DISABLE_THRESHOLD: u32 = 0x7;
|
||||||
|
const PLIC_ENABLE_THRESHOLD: u32 = 0;
|
||||||
|
|
||||||
|
const PLIC_QUIRK_EDGE_INTERRUPT: u32 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IrqChip for PlicIrqChip {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"SiFive PLIC"
|
||||||
|
}
|
||||||
|
fn irq_enable(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
|
// kwarn!("plic: irq_enable");
|
||||||
|
let common_data = irq_data.common_data();
|
||||||
|
let inner_guard = common_data.inner();
|
||||||
|
let mask = inner_guard.effective_affinity();
|
||||||
|
|
||||||
|
plic_irq_toggle(mask, irq_data, true);
|
||||||
|
self.irq_unmask(irq_data).expect("irq_unmask failed");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_unmask(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
|
// kwarn!("plic: irq_unmask");
|
||||||
|
|
||||||
|
let chip_data = irq_data
|
||||||
|
.chip_info_read_irqsave()
|
||||||
|
.chip_data()
|
||||||
|
.ok_or(SystemError::EINVAL)?;
|
||||||
|
let plic_chip_data = chip_data
|
||||||
|
.as_any_ref()
|
||||||
|
.downcast_ref::<PlicChipData>()
|
||||||
|
.ok_or(SystemError::EINVAL)?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
core::ptr::write_volatile(
|
||||||
|
(plic_chip_data.regs
|
||||||
|
+ PlicIrqChip::PRIORITY_BASE
|
||||||
|
+ irq_data.hardware_irq().data() as usize * PlicIrqChip::PRIORITY_PER_ID)
|
||||||
|
.data() as *mut u32,
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_mask(&self, irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
|
let chip_data = irq_data
|
||||||
|
.chip_info_read_irqsave()
|
||||||
|
.chip_data()
|
||||||
|
.ok_or(SystemError::EINVAL)?;
|
||||||
|
let plic_chip_data = chip_data
|
||||||
|
.as_any_ref()
|
||||||
|
.downcast_ref::<PlicChipData>()
|
||||||
|
.ok_or(SystemError::EINVAL)?;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
core::ptr::write_volatile(
|
||||||
|
(plic_chip_data.regs
|
||||||
|
+ PlicIrqChip::PRIORITY_BASE
|
||||||
|
+ irq_data.hardware_irq().data() as usize * PlicIrqChip::PRIORITY_PER_ID)
|
||||||
|
.data() as *mut u32,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_disable(&self, irq_data: &Arc<IrqData>) {
|
||||||
|
kdebug!("plic: irq_disable");
|
||||||
|
let common_data = irq_data.common_data();
|
||||||
|
let inner_guard = common_data.inner();
|
||||||
|
let mask = inner_guard.effective_affinity();
|
||||||
|
plic_irq_toggle(mask, irq_data, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_eoi(&self, irq_data: &Arc<IrqData>) {
|
||||||
|
let handler = plic_handlers().get();
|
||||||
|
|
||||||
|
if core::intrinsics::unlikely(irq_data.common_data().disabled()) {
|
||||||
|
handler.toggle(irq_data.hardware_irq(), true);
|
||||||
|
unsafe {
|
||||||
|
write_volatile(
|
||||||
|
(handler.inner().hart_base + PlicIrqChip::CONTEXT_CLAIM).data() as *mut u32,
|
||||||
|
irq_data.hardware_irq().data(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handler.toggle(irq_data.hardware_irq(), false);
|
||||||
|
} else {
|
||||||
|
// kdebug!("plic: irq_eoi: hwirq: {:?}", irq_data.hardware_irq());
|
||||||
|
unsafe {
|
||||||
|
write_volatile(
|
||||||
|
(handler.inner().hart_base + PlicIrqChip::CONTEXT_CLAIM).data() as *mut u32,
|
||||||
|
irq_data.hardware_irq().data(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_ack(&self, _irq: &Arc<IrqData>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_mask_ack(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_set_affinity(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 设置中断的亲和性
|
||||||
|
///
|
||||||
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c#161
|
||||||
|
fn irq_set_affinity(
|
||||||
|
&self,
|
||||||
|
irq_data: &Arc<IrqData>,
|
||||||
|
mask_val: &CpuMask,
|
||||||
|
force: bool,
|
||||||
|
) -> Result<IrqChipSetMaskResult, SystemError> {
|
||||||
|
let chip_data = irq_data
|
||||||
|
.chip_info_read_irqsave()
|
||||||
|
.chip_data()
|
||||||
|
.ok_or(SystemError::EINVAL)?;
|
||||||
|
let plic_chip_data = chip_data
|
||||||
|
.as_any_ref()
|
||||||
|
.downcast_ref::<PlicChipData>()
|
||||||
|
.ok_or(SystemError::EINVAL)?;
|
||||||
|
|
||||||
|
let mut amask = plic_chip_data.lmask().deref() & mask_val;
|
||||||
|
let cpu = if force {
|
||||||
|
mask_val.first()
|
||||||
|
} else {
|
||||||
|
amask.bitand_assign(smp_cpu_manager().possible_cpus());
|
||||||
|
// todo: 随机选择一个CPU
|
||||||
|
amask.first()
|
||||||
|
}
|
||||||
|
.ok_or(SystemError::EINVAL)?;
|
||||||
|
|
||||||
|
if cpu.data() > smp_cpu_manager().present_cpus_count() {
|
||||||
|
return Err(SystemError::EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.irq_disable(irq_data);
|
||||||
|
irq_data
|
||||||
|
.common_data()
|
||||||
|
.set_effective_affinity(CpuMask::from_cpu(cpu));
|
||||||
|
if !irq_data.common_data().disabled() {
|
||||||
|
self.irq_enable(irq_data).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(IrqChipSetMaskResult::Done)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_set_flow_type(&self) -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flags(&self) -> IrqChipFlags {
|
||||||
|
IrqChipFlags::empty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn riscv_sifive_plic_init() -> Result<(), SystemError> {
|
||||||
|
static INIT_PLIC_IRQ_CHIP_ONCE: Once = Once::new();
|
||||||
|
INIT_PLIC_IRQ_CHIP_ONCE.call_once(|| unsafe {
|
||||||
|
PLIC_IRQ_CHIP = Some(Arc::new(PlicIrqChip));
|
||||||
|
|
||||||
|
PLIC_HANDLERS = Some(
|
||||||
|
PerCpuVar::new(
|
||||||
|
(0..PerCpu::MAX_CPU_NUM)
|
||||||
|
.map(|_| PlicHandler::new())
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let fdt = open_firmware_fdt_driver().fdt_ref()?;
|
||||||
|
let all_plics = fdt.all_nodes().filter(|x| {
|
||||||
|
if let Some(compatible) = x.compatible() {
|
||||||
|
compatible
|
||||||
|
.all()
|
||||||
|
.any(|x| x == PlicIrqChip::COMPATIBLE || x == "riscv,plic0")
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for node in all_plics {
|
||||||
|
if let Err(e) = do_riscv_sifive_plic_init(&node) {
|
||||||
|
kwarn!("Failed to init SiFive PLIC: node: {node:?} {e:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe { riscv::register::sie::set_sext() };
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 初始化SiFive PLIC
|
||||||
|
///
|
||||||
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c#415
|
||||||
|
fn do_riscv_sifive_plic_init(fdt_node: &FdtNode) -> Result<(), SystemError> {
|
||||||
|
let reg = fdt_node
|
||||||
|
.reg()
|
||||||
|
.ok_or(SystemError::EINVAL)?
|
||||||
|
.next()
|
||||||
|
.ok_or(SystemError::EIO)?;
|
||||||
|
let paddr = PhysAddr::new(reg.starting_address as usize);
|
||||||
|
let size = reg.size.ok_or(SystemError::EINVAL)?;
|
||||||
|
let mmio_guard = mmio_pool().create_mmio(size)?;
|
||||||
|
let vaddr = unsafe { mmio_guard.map_any_phys(paddr, size) }?;
|
||||||
|
|
||||||
|
let phandle = fdt_node
|
||||||
|
.property("phandle")
|
||||||
|
.ok_or(SystemError::EINVAL)?
|
||||||
|
.as_usize()
|
||||||
|
.ok_or(SystemError::EINVAL)?;
|
||||||
|
|
||||||
|
// 中断数量
|
||||||
|
let irq_num = fdt_node
|
||||||
|
.property("riscv,ndev")
|
||||||
|
.ok_or(SystemError::EINVAL)?
|
||||||
|
.as_usize()
|
||||||
|
.ok_or(SystemError::EINVAL)?;
|
||||||
|
kdebug!(
|
||||||
|
"plic: node: {}, irq_num: {irq_num}, paddr: {paddr:?}, size: {size}",
|
||||||
|
fdt_node.name
|
||||||
|
);
|
||||||
|
let nr_contexts = fdt_node
|
||||||
|
.interrupts_extended()
|
||||||
|
.ok_or(SystemError::EINVAL)?
|
||||||
|
.count();
|
||||||
|
kdebug!("plic: nr_contexts: {nr_contexts}");
|
||||||
|
|
||||||
|
let irq_domain = irq_domain_manager()
|
||||||
|
.create_and_add_linear(
|
||||||
|
fdt_node.name.to_string(),
|
||||||
|
&PlicIrqDomainOps,
|
||||||
|
(irq_num + 1) as u32,
|
||||||
|
)
|
||||||
|
.ok_or(SystemError::EINVAL)?;
|
||||||
|
// kdebug!("plic: irq_domain: {irq_domain:?}");
|
||||||
|
|
||||||
|
let priv_data = PlicChipData::new(
|
||||||
|
Arc::downgrade(&irq_domain),
|
||||||
|
mmio_guard,
|
||||||
|
vaddr,
|
||||||
|
phandle as u32,
|
||||||
|
);
|
||||||
|
irq_domain.set_host_data(Some(priv_data.clone() as Arc<dyn IrqChipData>));
|
||||||
|
|
||||||
|
let loop_done_setup = |irq_handler: &PlicHandler| {
|
||||||
|
for x in 1..=irq_num {
|
||||||
|
irq_handler.toggle(HardwareIrqNumber::new(x as u32), false);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
core::ptr::write_volatile(
|
||||||
|
(priv_data.regs + PlicIrqChip::PRIORITY_BASE + x * PlicIrqChip::PRIORITY_PER_ID)
|
||||||
|
.data() as *mut u32,
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// todo: 学习linux那样处理,获取到hartid,这里暂时糊代码
|
||||||
|
// linux: https://code.dragonos.org.cn/xref/linux-6.6.21/drivers/irqchip/irq-sifive-plic.c#458
|
||||||
|
for i in smp_cpu_manager().present_cpus().iter_cpu() {
|
||||||
|
let i = i.data() as usize;
|
||||||
|
|
||||||
|
let cpu = ProcessorId::new(i as u32);
|
||||||
|
let handler = unsafe { plic_handlers().force_get(cpu) };
|
||||||
|
if handler.present() {
|
||||||
|
kwarn!("plic: handler {i} already present.");
|
||||||
|
handler.set_threshold(PlicIrqChip::PLIC_ENABLE_THRESHOLD);
|
||||||
|
loop_done_setup(handler);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kdebug!("plic: setup lmask {cpu:?}.");
|
||||||
|
priv_data.lmask().set(cpu, true);
|
||||||
|
let mut handler_inner = handler.inner();
|
||||||
|
handler_inner.hart_base =
|
||||||
|
priv_data.regs + PlicIrqChip::CONTEXT_BASE + i * PlicIrqChip::CONTEXT_SIZE;
|
||||||
|
handler_inner.enable_base = priv_data.regs
|
||||||
|
+ PlicIrqChip::CONTEXT_ENABLE_BASE
|
||||||
|
+ i * PlicIrqChip::CONTEXT_ENABLE_SIZE;
|
||||||
|
handler.set_present(true);
|
||||||
|
unsafe {
|
||||||
|
plic_handlers()
|
||||||
|
.force_get_mut(cpu)
|
||||||
|
.force_set_priv_data(priv_data.clone())
|
||||||
|
};
|
||||||
|
|
||||||
|
handler_inner.enable_save = Some(AllocBitmap::new(irq_num as usize));
|
||||||
|
|
||||||
|
drop(handler_inner);
|
||||||
|
handler.set_threshold(PlicIrqChip::PLIC_ENABLE_THRESHOLD);
|
||||||
|
|
||||||
|
loop_done_setup(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 把外部设备的中断与PLIC关联起来
|
||||||
|
associate_irq_with_plic_domain(&irq_domain, phandle as u32).ok();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 把设备的中断与PLIC的关联起来
|
||||||
|
fn associate_irq_with_plic_domain(
|
||||||
|
irq_domain: &Arc<IrqDomain>,
|
||||||
|
plic_phandle: u32,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
let fdt_ref = open_firmware_fdt_driver().fdt_ref()?;
|
||||||
|
let nodes = fdt_ref.all_nodes().filter(|x| {
|
||||||
|
if let Some(pa) = x.property("interrupt-parent").and_then(|x| x.as_usize()) {
|
||||||
|
pa as u32 == plic_phandle
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for node in nodes {
|
||||||
|
if let Some(irq) = node.interrupts().and_then(|mut x| x.next()) {
|
||||||
|
let irq = irq as u32;
|
||||||
|
let virq = IrqNumber::new(irq);
|
||||||
|
let hwirq = HardwareIrqNumber::new(irq);
|
||||||
|
kdebug!("plic: associate irq: {irq}, virq: {virq:?}, hwirq: {hwirq:?}");
|
||||||
|
irq_domain_manager()
|
||||||
|
.domain_associate(irq_domain, virq, hwirq)
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct PlicIrqDomainOps;
|
||||||
|
|
||||||
|
impl IrqDomainOps for PlicIrqDomainOps {
|
||||||
|
fn unmap(&self, _irq_domain: &Arc<IrqDomain>, _virq: IrqNumber) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn map(
|
||||||
|
&self,
|
||||||
|
irq_domain: &Arc<IrqDomain>,
|
||||||
|
hwirq: HardwareIrqNumber,
|
||||||
|
virq: IrqNumber,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
// kdebug!("plic: map: virq: {virq:?}, hwirq: {hwirq:?}");
|
||||||
|
|
||||||
|
let chip_data = irq_domain.host_data().ok_or(SystemError::EINVAL)?;
|
||||||
|
let plic_chip_data = chip_data
|
||||||
|
.as_any_ref()
|
||||||
|
.downcast_ref::<PlicChipData>()
|
||||||
|
.ok_or(SystemError::EINVAL)?;
|
||||||
|
irq_domain_manager().domain_set_info(
|
||||||
|
irq_domain,
|
||||||
|
virq,
|
||||||
|
hwirq,
|
||||||
|
plic_irq_chip(),
|
||||||
|
irq_domain.host_data(),
|
||||||
|
fast_eoi_irq_handler(),
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
let irq_desc = irq_desc_manager().lookup(virq).unwrap();
|
||||||
|
irq_desc.set_noprobe();
|
||||||
|
let mask = plic_chip_data.lmask().clone();
|
||||||
|
irq_manager().irq_set_affinity(&irq_desc.irq_data(), &irq_desc.inner(), &mask)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn activate(
|
||||||
|
&self,
|
||||||
|
_domain: &Arc<IrqDomain>,
|
||||||
|
_irq_data: &Arc<IrqData>,
|
||||||
|
_reserve: bool,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
kwarn!("plic: activate");
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deactivate(&self, _domain: &Arc<IrqDomain>, _irq_data: &Arc<IrqData>) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 处理PLIC中断
|
||||||
|
pub(super) fn do_plic_irq(trap_frame: &mut TrapFrame) {
|
||||||
|
// kdebug!("plic: do_plic_irq");
|
||||||
|
|
||||||
|
let handler = plic_handlers().get();
|
||||||
|
let priv_data = handler.priv_data();
|
||||||
|
if priv_data.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let domain = priv_data.unwrap().irq_domain.upgrade();
|
||||||
|
if domain.is_none() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let domain = domain.unwrap();
|
||||||
|
|
||||||
|
// 循环处理中断
|
||||||
|
loop {
|
||||||
|
let claim = unsafe {
|
||||||
|
read_volatile(
|
||||||
|
(handler.inner().hart_base + PlicIrqChip::CONTEXT_CLAIM).data() as *const u32,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if claim == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
kdebug!("plic: claim: {claim:?}");
|
||||||
|
|
||||||
|
let hwirq = HardwareIrqNumber::new(claim);
|
||||||
|
if let Err(e) = GenericIrqHandler::handle_domain_irq(domain.clone(), hwirq, trap_frame) {
|
||||||
|
kwarn!("plic: can't find mapping for hwirq {hwirq:?}, {e:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -207,6 +207,10 @@ impl VirtIODevice for VirtioInterface {
|
|||||||
return Ok(IrqReturn::Handled);
|
return Ok(IrqReturn::Handled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn irq(&self) -> Option<IrqNumber> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn dev_id(&self) -> &Arc<DeviceId> {
|
fn dev_id(&self) -> &Arc<DeviceId> {
|
||||||
return &self.dev_id;
|
return &self.dev_id;
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,16 @@ use hashbrown::HashMap;
|
|||||||
use system_error::SystemError;
|
use system_error::SystemError;
|
||||||
use unified_init::macros::unified_init;
|
use unified_init::macros::unified_init;
|
||||||
|
|
||||||
use crate::{driver::base::device::DeviceId, init::initcall::INITCALL_CORE, libs::rwlock::RwLock};
|
use crate::{
|
||||||
|
driver::base::device::DeviceId,
|
||||||
|
exception::{
|
||||||
|
irqdata::IrqHandlerData,
|
||||||
|
irqdesc::{IrqHandler, IrqReturn},
|
||||||
|
IrqNumber,
|
||||||
|
},
|
||||||
|
init::initcall::INITCALL_CORE,
|
||||||
|
libs::rwlock::RwLock,
|
||||||
|
};
|
||||||
|
|
||||||
use super::VirtIODevice;
|
use super::VirtIODevice;
|
||||||
|
|
||||||
@ -83,3 +92,36 @@ fn init_virtio_irq_manager() -> Result<(), SystemError> {
|
|||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `DefaultVirtioIrqHandler` 是一个默认的virtio设备中断处理程序。
|
||||||
|
///
|
||||||
|
/// 当虚拟设备产生中断时,该处理程序会被调用。
|
||||||
|
///
|
||||||
|
/// 它首先检查设备ID是否存在,然后尝试查找与设备ID关联的设备。
|
||||||
|
/// 如果找到设备,它会调用设备的 `handle_irq` 方法来处理中断。
|
||||||
|
/// 如果没有找到设备,它会记录一条警告并返回 `IrqReturn::NotHandled`,表示中断未被处理。
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(super) struct DefaultVirtioIrqHandler;
|
||||||
|
|
||||||
|
impl IrqHandler for DefaultVirtioIrqHandler {
|
||||||
|
fn handle(
|
||||||
|
&self,
|
||||||
|
irq: IrqNumber,
|
||||||
|
_static_data: Option<&dyn IrqHandlerData>,
|
||||||
|
dev_id: Option<Arc<dyn IrqHandlerData>>,
|
||||||
|
) -> Result<IrqReturn, SystemError> {
|
||||||
|
let dev_id = dev_id.ok_or(SystemError::EINVAL)?;
|
||||||
|
let dev_id = dev_id
|
||||||
|
.arc_any()
|
||||||
|
.downcast::<DeviceId>()
|
||||||
|
.map_err(|_| SystemError::EINVAL)?;
|
||||||
|
|
||||||
|
if let Some(dev) = virtio_irq_manager().lookup_device(&dev_id) {
|
||||||
|
return dev.handle_irq(irq);
|
||||||
|
} else {
|
||||||
|
// 未绑定具体设备,因此无法处理中断
|
||||||
|
kwarn!("No device found for IRQ: {:?}", irq);
|
||||||
|
return Ok(IrqReturn::NotHandled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -36,6 +36,13 @@ pub trait VirtIODevice: Device {
|
|||||||
|
|
||||||
/// virtio 设备厂商
|
/// virtio 设备厂商
|
||||||
fn vendor(&self) -> u32;
|
fn vendor(&self) -> u32;
|
||||||
|
|
||||||
|
/// virtio设备的中断号
|
||||||
|
fn irq(&self) -> Option<IrqNumber>;
|
||||||
|
|
||||||
|
fn set_irq_number(&self, _irq: IrqNumber) -> Result<(), SystemError> {
|
||||||
|
Err(SystemError::ENOSYS)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait VirtIODriver: Driver {
|
pub trait VirtIODriver: Driver {
|
||||||
|
@ -8,16 +8,20 @@ use system_error::SystemError;
|
|||||||
use unified_init::macros::unified_init;
|
use unified_init::macros::unified_init;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
driver::base::{
|
driver::{
|
||||||
device::{
|
base::{
|
||||||
bus::{bus_manager, Bus},
|
device::{
|
||||||
device_manager,
|
bus::{bus_manager, Bus},
|
||||||
driver::{driver_manager, Driver},
|
device_manager,
|
||||||
Device,
|
driver::{driver_manager, Driver},
|
||||||
|
Device,
|
||||||
|
},
|
||||||
|
kobject::KObject,
|
||||||
|
subsys::SubSysPrivate,
|
||||||
},
|
},
|
||||||
kobject::KObject,
|
virtio::irq::{virtio_irq_manager, DefaultVirtioIrqHandler},
|
||||||
subsys::SubSysPrivate,
|
|
||||||
},
|
},
|
||||||
|
exception::{irqdesc::IrqHandleFlags, manage::irq_manager},
|
||||||
filesystem::{
|
filesystem::{
|
||||||
sysfs::{
|
sysfs::{
|
||||||
file::sysfs_emit_str, Attribute, AttributeGroup, SysFSOpsSupport, SYSFS_ATTR_MODE_RO,
|
file::sysfs_emit_str, Attribute, AttributeGroup, SysFSOpsSupport, SYSFS_ATTR_MODE_RO,
|
||||||
@ -175,7 +179,47 @@ impl VirtIODeviceManager {
|
|||||||
virtio_drv.probe(&dev)?;
|
virtio_drv.probe(&dev)?;
|
||||||
|
|
||||||
device_manager().add_device(dev.clone() as Arc<dyn Device>)?;
|
device_manager().add_device(dev.clone() as Arc<dyn Device>)?;
|
||||||
device_manager().add_groups(&(dev as Arc<dyn Device>), &[&VirtIODeviceAttrGroup])
|
let r = device_manager()
|
||||||
|
.add_groups(&(dev.clone() as Arc<dyn Device>), &[&VirtIODeviceAttrGroup]);
|
||||||
|
|
||||||
|
self.setup_irq(&dev).ok();
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # setup_irq - 设置中断
|
||||||
|
///
|
||||||
|
/// 为virtio设备设置中断。
|
||||||
|
fn setup_irq(&self, dev: &Arc<dyn VirtIODevice>) -> Result<(), SystemError> {
|
||||||
|
let irq = dev.irq().ok_or(SystemError::EINVAL)?;
|
||||||
|
if let Err(e) = irq_manager().request_irq(
|
||||||
|
irq,
|
||||||
|
dev.device_name(),
|
||||||
|
&DefaultVirtioIrqHandler,
|
||||||
|
IrqHandleFlags::IRQF_SHARED,
|
||||||
|
Some(dev.dev_id().clone()),
|
||||||
|
) {
|
||||||
|
kerror!(
|
||||||
|
"Failed to request irq for virtio device '{}': irq: {:?}, error {:?}",
|
||||||
|
dev.device_name(),
|
||||||
|
irq,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtio_irq_manager()
|
||||||
|
.register_device(dev.clone())
|
||||||
|
.map_err(|e| {
|
||||||
|
kerror!(
|
||||||
|
"Failed to register virtio device's irq, dev: '{}', irq: {:?}, error {:?}",
|
||||||
|
dev.device_name(),
|
||||||
|
irq,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
e
|
||||||
|
})?;
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
use virtio_drivers::transport::Transport;
|
use virtio_drivers::transport::Transport;
|
||||||
|
|
||||||
|
use crate::exception::HardwareIrqNumber;
|
||||||
|
|
||||||
use super::{transport_mmio::VirtIOMmioTransport, transport_pci::PciTransport};
|
use super::{transport_mmio::VirtIOMmioTransport, transport_pci::PciTransport};
|
||||||
|
|
||||||
pub enum VirtIOTransport {
|
pub enum VirtIOTransport {
|
||||||
@ -7,6 +9,15 @@ pub enum VirtIOTransport {
|
|||||||
Mmio(VirtIOMmioTransport),
|
Mmio(VirtIOMmioTransport),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VirtIOTransport {
|
||||||
|
pub fn irq(&self) -> Option<HardwareIrqNumber> {
|
||||||
|
match self {
|
||||||
|
VirtIOTransport::Mmio(transport) => Some(transport.irq()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl core::fmt::Debug for VirtIOTransport {
|
impl core::fmt::Debug for VirtIOTransport {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
@ -8,9 +8,6 @@ use crate::driver::pci::pci::{
|
|||||||
|
|
||||||
use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqSpecificMsg, PciInterrupt, PciIrqMsg, IRQ};
|
use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqSpecificMsg, PciInterrupt, PciIrqMsg, IRQ};
|
||||||
use crate::driver::pci::root::pci_root_0;
|
use crate::driver::pci::root::pci_root_0;
|
||||||
use crate::driver::virtio::irq::virtio_irq_manager;
|
|
||||||
use crate::exception::irqdata::IrqHandlerData;
|
|
||||||
use crate::exception::irqdesc::{IrqHandler, IrqReturn};
|
|
||||||
|
|
||||||
use crate::exception::IrqNumber;
|
use crate::exception::IrqNumber;
|
||||||
|
|
||||||
@ -26,12 +23,12 @@ use core::{
|
|||||||
mem::{align_of, size_of},
|
mem::{align_of, size_of},
|
||||||
ptr::{self, addr_of_mut, NonNull},
|
ptr::{self, addr_of_mut, NonNull},
|
||||||
};
|
};
|
||||||
use system_error::SystemError;
|
|
||||||
use virtio_drivers::{
|
use virtio_drivers::{
|
||||||
transport::{DeviceStatus, DeviceType, Transport},
|
transport::{DeviceStatus, DeviceType, Transport},
|
||||||
Error, Hal, PhysAddr,
|
Error, Hal, PhysAddr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::irq::DefaultVirtioIrqHandler;
|
||||||
use super::VIRTIO_VENDOR_ID;
|
use super::VIRTIO_VENDOR_ID;
|
||||||
|
|
||||||
/// The offset to add to a VirtIO device ID to get the corresponding PCI device ID.
|
/// The offset to add to a VirtIO device ID to get the corresponding PCI device ID.
|
||||||
@ -569,36 +566,3 @@ fn get_bar_region_slice<T>(
|
|||||||
fn nonnull_slice_from_raw_parts<T>(data: NonNull<T>, len: usize) -> NonNull<[T]> {
|
fn nonnull_slice_from_raw_parts<T>(data: NonNull<T>, len: usize) -> NonNull<[T]> {
|
||||||
NonNull::new(ptr::slice_from_raw_parts_mut(data.as_ptr(), len)).unwrap()
|
NonNull::new(ptr::slice_from_raw_parts_mut(data.as_ptr(), len)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `DefaultVirtioIrqHandler` 是一个默认的virtio设备中断处理程序。
|
|
||||||
///
|
|
||||||
/// 当虚拟设备产生中断时,该处理程序会被调用。
|
|
||||||
///
|
|
||||||
/// 它首先检查设备ID是否存在,然后尝试查找与设备ID关联的设备。
|
|
||||||
/// 如果找到设备,它会调用设备的 `handle_irq` 方法来处理中断。
|
|
||||||
/// 如果没有找到设备,它会记录一条警告并返回 `IrqReturn::NotHandled`,表示中断未被处理。
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct DefaultVirtioIrqHandler;
|
|
||||||
|
|
||||||
impl IrqHandler for DefaultVirtioIrqHandler {
|
|
||||||
fn handle(
|
|
||||||
&self,
|
|
||||||
irq: IrqNumber,
|
|
||||||
_static_data: Option<&dyn IrqHandlerData>,
|
|
||||||
dev_id: Option<Arc<dyn IrqHandlerData>>,
|
|
||||||
) -> Result<IrqReturn, SystemError> {
|
|
||||||
let dev_id = dev_id.ok_or(SystemError::EINVAL)?;
|
|
||||||
let dev_id = dev_id
|
|
||||||
.arc_any()
|
|
||||||
.downcast::<DeviceId>()
|
|
||||||
.map_err(|_| SystemError::EINVAL)?;
|
|
||||||
|
|
||||||
if let Some(dev) = virtio_irq_manager().lookup_device(&dev_id) {
|
|
||||||
return dev.handle_irq(irq);
|
|
||||||
} else {
|
|
||||||
// 未绑定具体设备,因此无法处理中断
|
|
||||||
|
|
||||||
return Ok(IrqReturn::NotHandled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -5,13 +5,14 @@ use system_error::SystemError;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{interrupt::TrapFrame, CurrentIrqArch},
|
arch::{interrupt::TrapFrame, CurrentIrqArch},
|
||||||
exception::irqdesc::InnerIrqDesc,
|
exception::{irqchip::IrqChipFlags, irqdesc::InnerIrqDesc},
|
||||||
libs::{once::Once, spinlock::SpinLockGuard},
|
libs::{once::Once, spinlock::SpinLockGuard},
|
||||||
process::{ProcessFlags, ProcessManager},
|
process::{ProcessFlags, ProcessManager},
|
||||||
smp::core::smp_get_processor_id,
|
smp::core::smp_get_processor_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
irqchip::IrqChip,
|
||||||
irqdata::{IrqData, IrqHandlerData, IrqStatus},
|
irqdata::{IrqData, IrqHandlerData, IrqStatus},
|
||||||
irqdesc::{
|
irqdesc::{
|
||||||
InnerIrqAction, IrqDesc, IrqDescState, IrqFlowHandler, IrqReturn, ThreadedHandlerFlags,
|
InnerIrqAction, IrqDesc, IrqDescState, IrqFlowHandler, IrqReturn, ThreadedHandlerFlags,
|
||||||
@ -34,6 +35,7 @@ pub fn fast_eoi_irq_handler() -> &'static dyn IrqFlowHandler {
|
|||||||
|
|
||||||
/// 获取用于处理边沿触发中断的处理程序
|
/// 获取用于处理边沿触发中断的处理程序
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn edge_irq_handler() -> &'static dyn IrqFlowHandler {
|
pub fn edge_irq_handler() -> &'static dyn IrqFlowHandler {
|
||||||
&EdgeIrqHandler
|
&EdgeIrqHandler
|
||||||
}
|
}
|
||||||
@ -55,9 +57,38 @@ impl IrqFlowHandler for HandleBadIrq {
|
|||||||
struct FastEOIIrqHandler;
|
struct FastEOIIrqHandler;
|
||||||
|
|
||||||
impl IrqFlowHandler for FastEOIIrqHandler {
|
impl IrqFlowHandler for FastEOIIrqHandler {
|
||||||
fn handle(&self, _irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
|
/// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/chip.c?r=&mo=17578&fi=689#689
|
||||||
// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/chip.c?r=&mo=17578&fi=689#689
|
fn handle(&self, irq_desc: &Arc<IrqDesc>, _trap_frame: &mut TrapFrame) {
|
||||||
todo!("FastEOIIrqHandler");
|
let chip = irq_desc.irq_data().chip_info_read_irqsave().chip();
|
||||||
|
|
||||||
|
let mut desc_inner = irq_desc.inner();
|
||||||
|
let out = |din: SpinLockGuard<InnerIrqDesc>| {
|
||||||
|
if !chip.flags().contains(IrqChipFlags::IRQCHIP_EOI_IF_HANDLED) {
|
||||||
|
chip.irq_eoi(din.irq_data());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if !irq_may_run(&desc_inner) {
|
||||||
|
out(desc_inner);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc_inner
|
||||||
|
.internal_state_mut()
|
||||||
|
.remove(IrqDescState::IRQS_REPLAY | IrqDescState::IRQS_WAITING);
|
||||||
|
|
||||||
|
if desc_inner.actions().is_empty() || desc_inner.common_data().disabled() {
|
||||||
|
desc_inner
|
||||||
|
.internal_state_mut()
|
||||||
|
.insert(IrqDescState::IRQS_PENDING);
|
||||||
|
mask_irq(desc_inner.irq_data());
|
||||||
|
out(desc_inner);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
desc_inner = handle_irq_event(irq_desc, desc_inner);
|
||||||
|
cond_unmask_eoi_irq(&desc_inner, &chip);
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,17 +143,7 @@ impl IrqFlowHandler for EdgeIrqHandler {
|
|||||||
|
|
||||||
// kdebug!("handle_irq_event");
|
// kdebug!("handle_irq_event");
|
||||||
|
|
||||||
desc_inner_guard
|
desc_inner_guard = handle_irq_event(irq_desc, desc_inner_guard);
|
||||||
.internal_state_mut()
|
|
||||||
.remove(IrqDescState::IRQS_PENDING);
|
|
||||||
desc_inner_guard.common_data().set_inprogress();
|
|
||||||
|
|
||||||
drop(desc_inner_guard);
|
|
||||||
|
|
||||||
let _r = do_handle_irq_event(irq_desc);
|
|
||||||
|
|
||||||
desc_inner_guard = irq_desc.inner();
|
|
||||||
desc_inner_guard.common_data().clear_inprogress();
|
|
||||||
|
|
||||||
if !desc_inner_guard
|
if !desc_inner_guard
|
||||||
.internal_state()
|
.internal_state()
|
||||||
@ -160,6 +181,29 @@ pub(super) fn mask_ack_irq(irq_data: &Arc<IrqData>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) fn mask_irq(irq_data: &Arc<IrqData>) {
|
||||||
|
if irq_data.common_data().masked() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let chip = irq_data.chip_info_read_irqsave().chip();
|
||||||
|
if chip.irq_mask(irq_data).is_ok() {
|
||||||
|
irq_data.irqd_set(IrqStatus::IRQD_IRQ_MASKED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn unmask_irq(irq_data: &Arc<IrqData>) {
|
||||||
|
if !irq_data.common_data().masked() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let chip = irq_data.chip_info_read_irqsave().chip();
|
||||||
|
|
||||||
|
if chip.irq_unmask(irq_data).is_ok() {
|
||||||
|
irq_data.irqd_clear(IrqStatus::IRQD_IRQ_MASKED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl IrqManager {
|
impl IrqManager {
|
||||||
pub(super) fn do_irq_wake_thread(
|
pub(super) fn do_irq_wake_thread(
|
||||||
&self,
|
&self,
|
||||||
@ -191,6 +235,24 @@ impl IrqManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_irq_event<'a>(
|
||||||
|
irq_desc: &'a Arc<IrqDesc>,
|
||||||
|
mut desc_inner_guard: SpinLockGuard<'_, InnerIrqDesc>,
|
||||||
|
) -> SpinLockGuard<'a, InnerIrqDesc> {
|
||||||
|
desc_inner_guard
|
||||||
|
.internal_state_mut()
|
||||||
|
.remove(IrqDescState::IRQS_PENDING);
|
||||||
|
desc_inner_guard.common_data().set_inprogress();
|
||||||
|
|
||||||
|
drop(desc_inner_guard);
|
||||||
|
|
||||||
|
let _r = do_handle_irq_event(irq_desc);
|
||||||
|
|
||||||
|
let desc_inner_guard = irq_desc.inner();
|
||||||
|
desc_inner_guard.common_data().clear_inprogress();
|
||||||
|
|
||||||
|
return desc_inner_guard;
|
||||||
|
}
|
||||||
/// 处理中断事件
|
/// 处理中断事件
|
||||||
///
|
///
|
||||||
/// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/handle.c?fi=handle_irq_event#139
|
/// https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/handle.c?fi=handle_irq_event#139
|
||||||
@ -228,6 +290,47 @@ fn do_handle_irq_event(desc: &Arc<IrqDesc>) -> Result<(), SystemError> {
|
|||||||
return r.map(|_| ());
|
return r.map(|_| ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.1.9/kernel/irq/chip.c?r=&mo=17578&fi=659
|
||||||
|
fn cond_unmask_eoi_irq(
|
||||||
|
desc_inner_guard: &SpinLockGuard<'_, InnerIrqDesc>,
|
||||||
|
chip: &Arc<dyn IrqChip>,
|
||||||
|
) {
|
||||||
|
if !desc_inner_guard
|
||||||
|
.internal_state()
|
||||||
|
.contains(IrqDescState::IRQS_ONESHOT)
|
||||||
|
{
|
||||||
|
chip.irq_eoi(desc_inner_guard.irq_data());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to unmask in the following cases:
|
||||||
|
* - Oneshot irq which did not wake the thread (caused by a
|
||||||
|
* spurious interrupt or a primary handler handling it
|
||||||
|
* completely).
|
||||||
|
*/
|
||||||
|
|
||||||
|
if !desc_inner_guard.common_data().disabled()
|
||||||
|
&& desc_inner_guard.common_data().masked()
|
||||||
|
&& desc_inner_guard.threads_oneshot() == 0
|
||||||
|
{
|
||||||
|
kdebug!(
|
||||||
|
"eoi unmask irq {}",
|
||||||
|
desc_inner_guard.irq_data().irq().data()
|
||||||
|
);
|
||||||
|
chip.irq_eoi(desc_inner_guard.irq_data());
|
||||||
|
unmask_irq(desc_inner_guard.irq_data());
|
||||||
|
} else if !chip.flags().contains(IrqChipFlags::IRQCHIP_EOI_THREADED) {
|
||||||
|
kdebug!("eoi irq {}", desc_inner_guard.irq_data().irq().data());
|
||||||
|
chip.irq_eoi(desc_inner_guard.irq_data());
|
||||||
|
} else {
|
||||||
|
kwarn!(
|
||||||
|
"irq {} eoi failed",
|
||||||
|
desc_inner_guard.irq_data().irq().data()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn warn_no_thread(irq: IrqNumber, action_inner: &mut SpinLockGuard<'_, InnerIrqAction>) {
|
fn warn_no_thread(irq: IrqNumber, action_inner: &mut SpinLockGuard<'_, InnerIrqAction>) {
|
||||||
// warn on once
|
// warn on once
|
||||||
if action_inner
|
if action_inner
|
||||||
|
@ -37,27 +37,27 @@ use super::{
|
|||||||
pub trait IrqChip: Sync + Send + Any + Debug {
|
pub trait IrqChip: Sync + Send + Any + Debug {
|
||||||
fn name(&self) -> &'static str;
|
fn name(&self) -> &'static str;
|
||||||
/// start up the interrupt (defaults to ->enable if ENOSYS)
|
/// start up the interrupt (defaults to ->enable if ENOSYS)
|
||||||
fn irq_startup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
fn irq_startup(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
Err(SystemError::ENOSYS)
|
Err(SystemError::ENOSYS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// shut down the interrupt (defaults to ->disable if ENOSYS)
|
/// shut down the interrupt (defaults to ->disable if ENOSYS)
|
||||||
fn irq_shutdown(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
fn irq_shutdown(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
Err(SystemError::ENOSYS)
|
Err(SystemError::ENOSYS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// enable the interrupt
|
/// enable the interrupt
|
||||||
///
|
///
|
||||||
/// (defaults to ->unmask if ENOSYS)
|
/// (defaults to ->unmask if ENOSYS)
|
||||||
fn irq_enable(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
fn irq_enable(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
Err(SystemError::ENOSYS)
|
Err(SystemError::ENOSYS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// disable the interrupt
|
/// disable the interrupt
|
||||||
fn irq_disable(&self, irq: &Arc<IrqData>);
|
fn irq_disable(&self, irq_data: &Arc<IrqData>);
|
||||||
|
|
||||||
/// start of a new interrupt
|
/// start of a new interrupt
|
||||||
fn irq_ack(&self, irq: &Arc<IrqData>);
|
fn irq_ack(&self, irq_data: &Arc<IrqData>);
|
||||||
|
|
||||||
/// mask an interrupt source
|
/// mask an interrupt source
|
||||||
///
|
///
|
||||||
@ -66,7 +66,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
|||||||
/// 如果返回ENOSYS,则表明irq_mask()不支持. 那么中断机制代码将调用irq_disable()。
|
/// 如果返回ENOSYS,则表明irq_mask()不支持. 那么中断机制代码将调用irq_disable()。
|
||||||
///
|
///
|
||||||
/// 如果返回错误,那么中断的屏蔽状态将不会改变。
|
/// 如果返回错误,那么中断的屏蔽状态将不会改变。
|
||||||
fn irq_mask(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
fn irq_mask(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
Err(SystemError::ENOSYS)
|
Err(SystemError::ENOSYS)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,18 +74,18 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
|||||||
fn can_mask_ack(&self) -> bool;
|
fn can_mask_ack(&self) -> bool;
|
||||||
|
|
||||||
/// ack and mask an interrupt source
|
/// ack and mask an interrupt source
|
||||||
fn irq_mask_ack(&self, _irq: &Arc<IrqData>) {}
|
fn irq_mask_ack(&self, _irq_data: &Arc<IrqData>) {}
|
||||||
|
|
||||||
/// unmask an interrupt source
|
/// unmask an interrupt source
|
||||||
///
|
///
|
||||||
/// 用于取消屏蔽中断
|
/// 用于取消屏蔽中断
|
||||||
///
|
///
|
||||||
/// 如果返回ENOSYS,则表明irq_unmask()不支持.
|
/// 如果返回ENOSYS,则表明irq_unmask()不支持.
|
||||||
fn irq_unmask(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
fn irq_unmask(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
Err(SystemError::ENOSYS)
|
Err(SystemError::ENOSYS)
|
||||||
}
|
}
|
||||||
/// end of interrupt
|
/// end of interrupt
|
||||||
fn irq_eoi(&self, _irq: &Arc<IrqData>) {}
|
fn irq_eoi(&self, _irq_data: &Arc<IrqData>) {}
|
||||||
|
|
||||||
/// 指示当前芯片是否可以设置中断亲和性。
|
/// 指示当前芯片是否可以设置中断亲和性。
|
||||||
fn can_set_affinity(&self) -> bool;
|
fn can_set_affinity(&self) -> bool;
|
||||||
@ -96,7 +96,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
|||||||
/// 不需要对提供的亲和性掩码进行完整性检查。这用于CPU热插拔,其中目标CPU尚未在cpu_online_mask中设置。
|
/// 不需要对提供的亲和性掩码进行完整性检查。这用于CPU热插拔,其中目标CPU尚未在cpu_online_mask中设置。
|
||||||
fn irq_set_affinity(
|
fn irq_set_affinity(
|
||||||
&self,
|
&self,
|
||||||
_irq: &Arc<IrqData>,
|
_irq_data: &Arc<IrqData>,
|
||||||
_cpu: &CpuMask,
|
_cpu: &CpuMask,
|
||||||
_force: bool,
|
_force: bool,
|
||||||
) -> Result<IrqChipSetMaskResult, SystemError> {
|
) -> Result<IrqChipSetMaskResult, SystemError> {
|
||||||
@ -104,7 +104,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// retrigger an IRQ to the CPU
|
/// retrigger an IRQ to the CPU
|
||||||
fn retrigger(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
fn retrigger(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
Err(SystemError::ENOSYS)
|
Err(SystemError::ENOSYS)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,65 +119,65 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
|||||||
///
|
///
|
||||||
fn irq_set_type(
|
fn irq_set_type(
|
||||||
&self,
|
&self,
|
||||||
_irq: &Arc<IrqData>,
|
_irq_data: &Arc<IrqData>,
|
||||||
_flow_type: IrqLineStatus,
|
_flow_type: IrqLineStatus,
|
||||||
) -> Result<IrqChipSetMaskResult, SystemError> {
|
) -> Result<IrqChipSetMaskResult, SystemError> {
|
||||||
Err(SystemError::ENOSYS)
|
Err(SystemError::ENOSYS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// enable/disable power management wake-on of an interrupt
|
/// enable/disable power management wake-on of an interrupt
|
||||||
fn irq_set_wake(&self, _irq: &Arc<IrqData>, _on: bool) -> Result<(), SystemError> {
|
fn irq_set_wake(&self, _irq_data: &Arc<IrqData>, _on: bool) -> Result<(), SystemError> {
|
||||||
Err(SystemError::ENOSYS)
|
Err(SystemError::ENOSYS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// function to lock access to slow bus (i2c) chips
|
/// function to lock access to slow bus (i2c) chips
|
||||||
fn irq_bus_lock(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
fn irq_bus_lock(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// function to sync and unlock slow bus (i2c) chips
|
/// function to sync and unlock slow bus (i2c) chips
|
||||||
fn irq_bus_sync_unlock(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
fn irq_bus_sync_unlock(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// function called from core code on suspend once per
|
/// function called from core code on suspend once per
|
||||||
/// chip, when one or more interrupts are installed
|
/// chip, when one or more interrupts are installed
|
||||||
fn irq_suspend(&self, _irq: &Arc<IrqData>) {}
|
fn irq_suspend(&self, _irq_data: &Arc<IrqData>) {}
|
||||||
|
|
||||||
/// function called from core code on resume once per chip,
|
/// function called from core code on resume once per chip,
|
||||||
/// when one ore more interrupts are installed
|
/// when one ore more interrupts are installed
|
||||||
fn irq_resume(&self, _irq: &Arc<IrqData>) {}
|
fn irq_resume(&self, _irq_data: &Arc<IrqData>) {}
|
||||||
|
|
||||||
/// function called from core code on shutdown once per chip
|
/// function called from core code on shutdown once per chip
|
||||||
fn irq_pm_shutdown(&self, _irq: &Arc<IrqData>) {}
|
fn irq_pm_shutdown(&self, _irq_data: &Arc<IrqData>) {}
|
||||||
|
|
||||||
/// Optional function to set irq_data.mask for special cases
|
/// Optional function to set irq_data.mask for special cases
|
||||||
fn irq_calc_mask(&self, _irq: &Arc<IrqData>) {}
|
fn irq_calc_mask(&self, _irq_data: &Arc<IrqData>) {}
|
||||||
|
|
||||||
// todo: print chip
|
// todo: print chip
|
||||||
|
|
||||||
/// optional to request resources before calling
|
/// optional to request resources before calling
|
||||||
/// any other callback related to this irq
|
/// any other callback related to this irq
|
||||||
fn irq_request_resources(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
fn irq_request_resources(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// optional to release resources acquired with
|
/// optional to release resources acquired with
|
||||||
/// irq_request_resources
|
/// irq_request_resources
|
||||||
fn irq_release_resources(&self, _irq: &Arc<IrqData>) {}
|
fn irq_release_resources(&self, _irq_data: &Arc<IrqData>) {}
|
||||||
|
|
||||||
/// optional to compose message content for MSI
|
/// optional to compose message content for MSI
|
||||||
///
|
///
|
||||||
/// 组装MSI消息并返回到msg中
|
/// 组装MSI消息并返回到msg中
|
||||||
fn irq_compose_msi_msg(&self, _irq: &Arc<IrqData>, _msg: &mut MsiMsg) {}
|
fn irq_compose_msi_msg(&self, _irq_data: &Arc<IrqData>, _msg: &mut MsiMsg) {}
|
||||||
|
|
||||||
/// optional to write message content for MSI
|
/// optional to write message content for MSI
|
||||||
fn irq_write_msi_msg(&self, _irq: &Arc<IrqData>, _msg: &MsiMsg) {}
|
fn irq_write_msi_msg(&self, _irq_data: &Arc<IrqData>, _msg: &MsiMsg) {}
|
||||||
|
|
||||||
/// return the internal state of an interrupt
|
/// return the internal state of an interrupt
|
||||||
fn irqchip_state(
|
fn irqchip_state(
|
||||||
&self,
|
&self,
|
||||||
_irq: &Arc<IrqData>,
|
_irq_data: &Arc<IrqData>,
|
||||||
_which: IrqChipState,
|
_which: IrqChipState,
|
||||||
) -> Result<bool, SystemError> {
|
) -> Result<bool, SystemError> {
|
||||||
Err(SystemError::ENOSYS)
|
Err(SystemError::ENOSYS)
|
||||||
@ -186,7 +186,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
|||||||
/// set the internal state of an interrupt
|
/// set the internal state of an interrupt
|
||||||
fn set_irqchip_state(
|
fn set_irqchip_state(
|
||||||
&self,
|
&self,
|
||||||
_irq: &Arc<IrqData>,
|
_irq_data: &Arc<IrqData>,
|
||||||
_which: IrqChipState,
|
_which: IrqChipState,
|
||||||
_state: bool,
|
_state: bool,
|
||||||
) -> Result<(), SystemError> {
|
) -> Result<(), SystemError> {
|
||||||
@ -196,17 +196,17 @@ pub trait IrqChip: Sync + Send + Any + Debug {
|
|||||||
// todo: set vcpu affinity
|
// todo: set vcpu affinity
|
||||||
|
|
||||||
/// send a single IPI to destination cpus
|
/// send a single IPI to destination cpus
|
||||||
fn send_single_ipi(&self, _irq: &Arc<IrqData>, _cpu: u32) {}
|
fn send_single_ipi(&self, _irq_data: &Arc<IrqData>, _cpu: u32) {}
|
||||||
|
|
||||||
// todo: send ipi with cpu mask
|
// todo: send ipi with cpu mask
|
||||||
|
|
||||||
/// function called from core code before enabling an NMI
|
/// function called from core code before enabling an NMI
|
||||||
fn irq_nmi_setup(&self, _irq: &Arc<IrqData>) -> Result<(), SystemError> {
|
fn irq_nmi_setup(&self, _irq_data: &Arc<IrqData>) -> Result<(), SystemError> {
|
||||||
Err(SystemError::ENOSYS)
|
Err(SystemError::ENOSYS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// function called from core code after disabling an NMI
|
/// function called from core code after disabling an NMI
|
||||||
fn irq_nmi_teardown(&self, _irq: &Arc<IrqData>) {}
|
fn irq_nmi_teardown(&self, _irq_data: &Arc<IrqData>) {}
|
||||||
|
|
||||||
fn flags(&self) -> IrqChipFlags;
|
fn flags(&self) -> IrqChipFlags;
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,7 @@ impl IrqData {
|
|||||||
self.inner.lock_irqsave().desc = desc;
|
self.inner.lock_irqsave().desc = desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn clear_irq_desc(&self) {
|
pub fn clear_irq_desc(&self) {
|
||||||
self.inner.lock_irqsave().desc = Weak::new();
|
self.inner.lock_irqsave().desc = Weak::new();
|
||||||
}
|
}
|
||||||
@ -210,6 +211,7 @@ impl IrqCommonData {
|
|||||||
handler_data: None,
|
handler_data: None,
|
||||||
msi_desc: None,
|
msi_desc: None,
|
||||||
affinity: CpuMask::new(),
|
affinity: CpuMask::new(),
|
||||||
|
effective_affinity: CpuMask::new(),
|
||||||
};
|
};
|
||||||
return IrqCommonData {
|
return IrqCommonData {
|
||||||
inner: SpinLock::new(inner),
|
inner: SpinLock::new(inner),
|
||||||
@ -304,6 +306,10 @@ impl IrqCommonData {
|
|||||||
self.inner.lock_irqsave().affinity = affinity;
|
self.inner.lock_irqsave().affinity = affinity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_effective_affinity(&self, affinity: CpuMask) {
|
||||||
|
self.inner.lock_irqsave().effective_affinity = affinity;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn inner(&self) -> SpinLockGuard<InnerIrqCommonData> {
|
pub fn inner(&self) -> SpinLockGuard<InnerIrqCommonData> {
|
||||||
self.inner.lock_irqsave()
|
self.inner.lock_irqsave()
|
||||||
}
|
}
|
||||||
@ -318,6 +324,7 @@ pub struct InnerIrqCommonData {
|
|||||||
handler_data: Option<Arc<dyn IrqHandlerData>>,
|
handler_data: Option<Arc<dyn IrqHandlerData>>,
|
||||||
msi_desc: Option<Arc<MsiDesc>>,
|
msi_desc: Option<Arc<MsiDesc>>,
|
||||||
affinity: CpuMask,
|
affinity: CpuMask,
|
||||||
|
effective_affinity: CpuMask,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InnerIrqCommonData {
|
impl InnerIrqCommonData {
|
||||||
@ -338,6 +345,10 @@ impl InnerIrqCommonData {
|
|||||||
pub fn handler_data(&self) -> Option<Arc<dyn IrqHandlerData>> {
|
pub fn handler_data(&self) -> Option<Arc<dyn IrqHandlerData>> {
|
||||||
self.handler_data.clone()
|
self.handler_data.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn effective_affinity(&self) -> &CpuMask {
|
||||||
|
&self.effective_affinity
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 中断处理函数传入的数据
|
/// 中断处理函数传入的数据
|
||||||
|
@ -114,6 +114,7 @@ impl IrqDesc {
|
|||||||
kern_inode: None,
|
kern_inode: None,
|
||||||
kset: None,
|
kset: None,
|
||||||
parent_kobj: None,
|
parent_kobj: None,
|
||||||
|
threads_oneshot: 0,
|
||||||
}),
|
}),
|
||||||
request_mutex: Mutex::new(()),
|
request_mutex: Mutex::new(()),
|
||||||
handler: RwLock::new(None),
|
handler: RwLock::new(None),
|
||||||
@ -285,6 +286,14 @@ impl IrqDesc {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_probe(&self) {
|
||||||
|
self.modify_status(IrqLineStatus::IRQ_NOPROBE, IrqLineStatus::empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_noprobe(&self) {
|
||||||
|
self.modify_status(IrqLineStatus::empty(), IrqLineStatus::IRQ_NOPROBE);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn modify_status(&self, clear: IrqLineStatus, set: IrqLineStatus) {
|
pub fn modify_status(&self, clear: IrqLineStatus, set: IrqLineStatus) {
|
||||||
let mut desc_guard = self.inner();
|
let mut desc_guard = self.inner();
|
||||||
desc_guard.line_status.remove(clear);
|
desc_guard.line_status.remove(clear);
|
||||||
@ -365,6 +374,8 @@ pub struct InnerIrqDesc {
|
|||||||
/// per-cpu affinity
|
/// per-cpu affinity
|
||||||
percpu_affinity: Option<CpuMask>,
|
percpu_affinity: Option<CpuMask>,
|
||||||
// wait_for_threads: EventWaitQueue
|
// wait_for_threads: EventWaitQueue
|
||||||
|
/// bitfield to handle shared oneshot threads
|
||||||
|
threads_oneshot: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InnerIrqDesc {
|
impl InnerIrqDesc {
|
||||||
@ -444,6 +455,10 @@ impl InnerIrqDesc {
|
|||||||
!self.line_status.contains(IrqLineStatus::IRQ_NOTHREAD)
|
!self.line_status.contains(IrqLineStatus::IRQ_NOTHREAD)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn threads_oneshot(&self) -> u64 {
|
||||||
|
self.threads_oneshot
|
||||||
|
}
|
||||||
|
|
||||||
/// 中断是否可以设置CPU亲和性
|
/// 中断是否可以设置CPU亲和性
|
||||||
pub fn can_set_affinity(&self) -> bool {
|
pub fn can_set_affinity(&self) -> bool {
|
||||||
if !self.common_data.status().can_balance()
|
if !self.common_data.status().can_balance()
|
||||||
|
@ -110,8 +110,6 @@ impl IrqDomainManager {
|
|||||||
|
|
||||||
self.add_domain(domain.clone());
|
self.add_domain(domain.clone());
|
||||||
|
|
||||||
self.domain_associate_many(&domain, first_irq, first_hwirq, irq_size);
|
|
||||||
|
|
||||||
return Some(domain);
|
return Some(domain);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,6 +246,10 @@ impl IrqDomainManager {
|
|||||||
/// 这是调用 domain_ops->activate 以编程中断控制器的第二步,以便中断实际上可以被传递。
|
/// 这是调用 domain_ops->activate 以编程中断控制器的第二步,以便中断实际上可以被传递。
|
||||||
pub fn activate_irq(&self, irq_data: &Arc<IrqData>, reserve: bool) -> Result<(), SystemError> {
|
pub fn activate_irq(&self, irq_data: &Arc<IrqData>, reserve: bool) -> Result<(), SystemError> {
|
||||||
let mut r = Ok(());
|
let mut r = Ok(());
|
||||||
|
// kdebug!(
|
||||||
|
// "activate_irq: irq_data.common_data().status().is_activated()={}",
|
||||||
|
// irq_data.common_data().status().is_activated()
|
||||||
|
// );
|
||||||
if !irq_data.common_data().status().is_activated() {
|
if !irq_data.common_data().status().is_activated() {
|
||||||
r = self.do_activate_irq(Some(irq_data.clone()), reserve);
|
r = self.do_activate_irq(Some(irq_data.clone()), reserve);
|
||||||
}
|
}
|
||||||
@ -268,7 +270,9 @@ impl IrqDomainManager {
|
|||||||
let mut r = Ok(());
|
let mut r = Ok(());
|
||||||
|
|
||||||
if let Some(irq_data) = irq_data {
|
if let Some(irq_data) = irq_data {
|
||||||
|
// kdebug!("do_activate_irq: irq_data={:?}", irq_data);
|
||||||
if let Some(domain) = irq_data.domain() {
|
if let Some(domain) = irq_data.domain() {
|
||||||
|
// kdebug!("do_activate_irq: domain={:?}", domain.name());
|
||||||
let parent_data = irq_data.parent_data().and_then(|x| x.upgrade());
|
let parent_data = irq_data.parent_data().and_then(|x| x.upgrade());
|
||||||
if let Some(parent_data) = parent_data.clone() {
|
if let Some(parent_data) = parent_data.clone() {
|
||||||
r = self.do_activate_irq(Some(parent_data), reserve);
|
r = self.do_activate_irq(Some(parent_data), reserve);
|
||||||
|
@ -155,7 +155,7 @@ impl IrqManager {
|
|||||||
*action_guard.flags_mut() = flags;
|
*action_guard.flags_mut() = flags;
|
||||||
*action_guard.dev_id_mut() = dev_id;
|
*action_guard.dev_id_mut() = dev_id;
|
||||||
drop(action_guard);
|
drop(action_guard);
|
||||||
|
kdebug!("to inner_setup_irq");
|
||||||
return self.inner_setup_irq(irq, irqaction, desc);
|
return self.inner_setup_irq(irq, irqaction, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,6 +370,15 @@ impl IrqManager {
|
|||||||
|| ((old_guard.flags().bitxor(*action_guard.flags()))
|
|| ((old_guard.flags().bitxor(*action_guard.flags()))
|
||||||
.contains(IrqHandleFlags::IRQF_ONESHOT))
|
.contains(IrqHandleFlags::IRQF_ONESHOT))
|
||||||
{
|
{
|
||||||
|
kdebug!(
|
||||||
|
"Flags mismatch for irq {} (name: {}, flags: {:?}). old action name: {}, old flags: {:?}",
|
||||||
|
irq.data(),
|
||||||
|
action_guard.name(),
|
||||||
|
action_guard.flags(),
|
||||||
|
old_guard.name(),
|
||||||
|
old_guard.flags()
|
||||||
|
);
|
||||||
|
|
||||||
return Err(err_out_mismatch(
|
return Err(err_out_mismatch(
|
||||||
old_guard,
|
old_guard,
|
||||||
desc_inner_guard,
|
desc_inner_guard,
|
||||||
@ -383,6 +392,12 @@ impl IrqManager {
|
|||||||
if *old_guard.flags() & IrqHandleFlags::IRQF_PERCPU
|
if *old_guard.flags() & IrqHandleFlags::IRQF_PERCPU
|
||||||
!= *action_guard.flags() & IrqHandleFlags::IRQF_PERCPU
|
!= *action_guard.flags() & IrqHandleFlags::IRQF_PERCPU
|
||||||
{
|
{
|
||||||
|
kdebug!(
|
||||||
|
"Per-cpu mismatch for irq {} (name: {}, flags: {:?})",
|
||||||
|
irq.data(),
|
||||||
|
action_guard.name(),
|
||||||
|
action_guard.flags()
|
||||||
|
);
|
||||||
return Err(err_out_mismatch(
|
return Err(err_out_mismatch(
|
||||||
old_guard,
|
old_guard,
|
||||||
desc_inner_guard,
|
desc_inner_guard,
|
||||||
@ -436,6 +451,13 @@ impl IrqManager {
|
|||||||
if let Err(e) =
|
if let Err(e) =
|
||||||
self.do_set_irq_trigger(desc.clone(), &mut desc_inner_guard, trigger_type)
|
self.do_set_irq_trigger(desc.clone(), &mut desc_inner_guard, trigger_type)
|
||||||
{
|
{
|
||||||
|
kdebug!(
|
||||||
|
"Failed to set trigger type for irq {} (name: {}, flags: {:?}), error {:?}",
|
||||||
|
irq.data(),
|
||||||
|
action_guard.name(),
|
||||||
|
action_guard.flags(),
|
||||||
|
e
|
||||||
|
);
|
||||||
return Err(err_out_unlock(
|
return Err(err_out_unlock(
|
||||||
e,
|
e,
|
||||||
desc_inner_guard,
|
desc_inner_guard,
|
||||||
@ -445,9 +467,16 @@ impl IrqManager {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
kdebug!("to irq_activate");
|
||||||
// 激活中断。这种激活必须独立于IRQ_NOAUTOEN进行*desc_inner_guard.internal_state_mut() |= IrqDescState::IRQS_NOREQUEST;uest.
|
// 激活中断。这种激活必须独立于IRQ_NOAUTOEN进行*desc_inner_guard.internal_state_mut() |= IrqDescState::IRQS_NOREQUEST;uest.
|
||||||
if let Err(e) = self.irq_activate(&desc, &mut desc_inner_guard) {
|
if let Err(e) = self.irq_activate(&desc, &mut desc_inner_guard) {
|
||||||
|
kdebug!(
|
||||||
|
"Failed to activate irq {} (name: {}, flags: {:?}), error {:?}",
|
||||||
|
irq.data(),
|
||||||
|
action_guard.name(),
|
||||||
|
action_guard.flags(),
|
||||||
|
e
|
||||||
|
);
|
||||||
return Err(err_out_unlock(
|
return Err(err_out_unlock(
|
||||||
e,
|
e,
|
||||||
desc_inner_guard,
|
desc_inner_guard,
|
||||||
@ -599,6 +628,11 @@ impl IrqManager {
|
|||||||
desc_inner_guard: &mut SpinLockGuard<'_, InnerIrqDesc>,
|
desc_inner_guard: &mut SpinLockGuard<'_, InnerIrqDesc>,
|
||||||
resend: bool,
|
resend: bool,
|
||||||
) -> Result<(), SystemError> {
|
) -> Result<(), SystemError> {
|
||||||
|
kdebug!(
|
||||||
|
"irq_activate_and_startup: irq: {}, name: {:?}",
|
||||||
|
desc.irq().data(),
|
||||||
|
desc_inner_guard.name()
|
||||||
|
);
|
||||||
self.irq_activate(desc, desc_inner_guard)?;
|
self.irq_activate(desc, desc_inner_guard)?;
|
||||||
self.irq_startup(desc, desc_inner_guard, resend, Self::IRQ_START_FORCE)
|
self.irq_startup(desc, desc_inner_guard, resend, Self::IRQ_START_FORCE)
|
||||||
}
|
}
|
||||||
@ -625,6 +659,11 @@ impl IrqManager {
|
|||||||
resend: bool,
|
resend: bool,
|
||||||
force: bool,
|
force: bool,
|
||||||
) -> Result<(), SystemError> {
|
) -> Result<(), SystemError> {
|
||||||
|
kdebug!(
|
||||||
|
"irq_startup: irq: {}, name: {:?}",
|
||||||
|
desc_inner_guard.irq_data().irq().data(),
|
||||||
|
desc_inner_guard.name()
|
||||||
|
);
|
||||||
let mut ret = Ok(());
|
let mut ret = Ok(());
|
||||||
let irq_data = desc_inner_guard.irq_data().clone();
|
let irq_data = desc_inner_guard.irq_data().clone();
|
||||||
let affinity = desc_inner_guard.common_data().affinity();
|
let affinity = desc_inner_guard.common_data().affinity();
|
||||||
@ -745,7 +784,15 @@ impl IrqManager {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn irq_do_set_affinity(
|
pub fn irq_set_affinity(
|
||||||
|
&self,
|
||||||
|
irq_data: &Arc<IrqData>,
|
||||||
|
desc_inner_guard: &SpinLockGuard<'_, InnerIrqDesc>,
|
||||||
|
cpumask: &CpuMask,
|
||||||
|
) -> Result<(), SystemError> {
|
||||||
|
return self.irq_do_set_affinity(irq_data, desc_inner_guard, cpumask, false);
|
||||||
|
}
|
||||||
|
fn irq_do_set_affinity(
|
||||||
&self,
|
&self,
|
||||||
irq_data: &Arc<IrqData>,
|
irq_data: &Arc<IrqData>,
|
||||||
desc_inner_guard: &SpinLockGuard<'_, InnerIrqDesc>,
|
desc_inner_guard: &SpinLockGuard<'_, InnerIrqDesc>,
|
||||||
@ -1050,6 +1097,8 @@ impl IrqManager {
|
|||||||
/// ## 注意
|
/// ## 注意
|
||||||
///
|
///
|
||||||
/// 此函数不可以在中断上下文中调用。
|
/// 此函数不可以在中断上下文中调用。
|
||||||
|
///
|
||||||
|
/// 参考 https://code.dragonos.org.cn/xref/linux-6.6.21/kernel/irq/manage.c#2026
|
||||||
pub fn free_irq(&self, _irq: IrqNumber, _dev_id: Option<Arc<DeviceId>>) {
|
pub fn free_irq(&self, _irq: IrqNumber, _dev_id: Option<Arc<DeviceId>>) {
|
||||||
kwarn!("Unimplemented free_irq");
|
kwarn!("Unimplemented free_irq");
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,21 @@ impl CpuMask {
|
|||||||
Self { bmp }
|
Self { bmp }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # from_cpu - 从指定的CPU创建CPU掩码
|
||||||
|
///
|
||||||
|
/// 该函数用于根据给定的CPU标识创建一个CPU掩码,只有指定的CPU被设置为激活状态。
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
/// - `cpu`: `ProcessorId`,指定要设置为激活状态的CPU。
|
||||||
|
///
|
||||||
|
/// ## 返回值
|
||||||
|
/// - `Self`: 返回一个新的`CpuMask`实例,其中只有指定的CPU被设置为激活状态。
|
||||||
|
pub fn from_cpu(cpu: ProcessorId) -> Self {
|
||||||
|
let mut mask = Self::new();
|
||||||
|
mask.set(cpu, true);
|
||||||
|
mask
|
||||||
|
}
|
||||||
|
|
||||||
/// 获取CpuMask中的第一个cpu
|
/// 获取CpuMask中的第一个cpu
|
||||||
pub fn first(&self) -> Option<ProcessorId> {
|
pub fn first(&self) -> Option<ProcessorId> {
|
||||||
self.bmp
|
self.bmp
|
||||||
@ -86,14 +101,24 @@ impl CpuMask {
|
|||||||
pub fn inner(&self) -> &AllocBitmap {
|
pub fn inner(&self) -> &AllocBitmap {
|
||||||
&self.bmp
|
&self.bmp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bitand_assign(&mut self, rhs: &CpuMask) {
|
||||||
|
self.bmp.bitand_assign(&rhs.bmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BitAnd for CpuMask {
|
impl BitAnd for &CpuMask {
|
||||||
type Output = Self;
|
type Output = CpuMask;
|
||||||
|
|
||||||
fn bitand(self, rhs: Self) -> Self::Output {
|
fn bitand(self, rhs: &CpuMask) -> Self::Output {
|
||||||
let bmp = self.bmp & rhs.bmp;
|
let bmp = &self.bmp & &rhs.bmp;
|
||||||
Self { bmp }
|
CpuMask { bmp }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for CpuMask {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use crate::libs::align::{page_align_down, page_align_up};
|
||||||
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
|
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
|
||||||
use crate::mm::kernel_mapper::KernelMapper;
|
use crate::mm::kernel_mapper::KernelMapper;
|
||||||
use crate::mm::page::{PAGE_1G_SHIFT, PAGE_4K_SHIFT};
|
use crate::mm::page::{PAGE_1G_SHIFT, PAGE_4K_SHIFT};
|
||||||
@ -682,6 +683,41 @@ impl MMIOSpaceGuard {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # map_any_phys - 将任意物理地址映射到虚拟地址
|
||||||
|
///
|
||||||
|
/// 将指定的物理地址和长度映射到虚拟地址空间。
|
||||||
|
///
|
||||||
|
/// ## 参数
|
||||||
|
///
|
||||||
|
/// - `paddr`: 物理地址,需要被映射的起始地址。
|
||||||
|
/// - `length`: 要映射的物理地址长度。
|
||||||
|
///
|
||||||
|
/// ## 返回值
|
||||||
|
/// - `Ok(VirtAddr)`: 映射成功,返回虚拟地址的起始地址。
|
||||||
|
/// - `Err(SystemError)`: 映射失败,返回系统错误。
|
||||||
|
///
|
||||||
|
/// ## 副作用
|
||||||
|
///
|
||||||
|
/// 该函数会修改虚拟地址空间,将物理地址映射到虚拟地址。
|
||||||
|
///
|
||||||
|
/// ## Safety
|
||||||
|
///
|
||||||
|
/// 由于该函数涉及到内存操作,因此它是非安全的。确保在调用该函数时,你传入的物理地址是正确的。
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub unsafe fn map_any_phys(
|
||||||
|
&self,
|
||||||
|
paddr: PhysAddr,
|
||||||
|
length: usize,
|
||||||
|
) -> Result<VirtAddr, SystemError> {
|
||||||
|
let paddr_base = PhysAddr::new(page_align_down(paddr.data()));
|
||||||
|
let offset = paddr - paddr_base;
|
||||||
|
let vaddr_base = self.vaddr;
|
||||||
|
let vaddr = vaddr_base + offset;
|
||||||
|
|
||||||
|
self.map_phys(paddr_base, page_align_up(length + offset))?;
|
||||||
|
return Ok(vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
/// 泄露一个MMIO space guard,不会释放映射的空间
|
/// 泄露一个MMIO space guard,不会释放映射的空间
|
||||||
pub unsafe fn leak(self) {
|
pub unsafe fn leak(self) {
|
||||||
core::mem::forget(self);
|
core::mem::forget(self);
|
||||||
|
@ -64,6 +64,7 @@ impl CpuHpCpuState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub const fn thread(&self) -> &Option<Arc<ProcessControlBlock>> {
|
pub const fn thread(&self) -> &Option<Arc<ProcessControlBlock>> {
|
||||||
&self.thread
|
&self.thread
|
||||||
}
|
}
|
||||||
@ -305,6 +306,7 @@ pub fn smp_cpu_manager_init(boot_cpu: ProcessorId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unsafe { smp_cpu_manager().set_possible_cpu(boot_cpu, true) };
|
unsafe { smp_cpu_manager().set_possible_cpu(boot_cpu, true) };
|
||||||
|
unsafe { smp_cpu_manager().set_present_cpu(boot_cpu, true) };
|
||||||
|
|
||||||
SmpCpuManager::arch_init(boot_cpu);
|
SmpCpuManager::arch_init(boot_cpu);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user