feat:(riscv/intr) 实现riscv plic驱动,能处理外部中断 (#799)

* feat:(riscv/intr) 实现riscv plic驱动,能处理外部中断

- 实现riscv plic驱动,能处理外部中断
- 能收到virtio-blk的中断
- 实现fasteoi interrupt handler
This commit is contained in:
LoGin 2024-05-01 21:11:32 +08:00 committed by GitHub
parent 17dc558977
commit 0102d69fdd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
30 changed files with 1214 additions and 127 deletions

View File

@ -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"]}
system_error = { path = "crates/system_error" }
unified-init = { path = "crates/unified-init" }
virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers", rev = "448a781" }
fdt = "=0.1.5"
virtio-drivers = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/virtio-drivers", rev = "f91c807965" }
fdt = { git = "https://git.mirrors.dragonos.org.cn/DragonOS-Community/fdt", rev = "9862813020" }
uefi = { version = "=0.26.0", features = ["alloc"] }
uefi-raw = "=0.5.0"
paste = "=1.0.14"

View File

@ -20,6 +20,12 @@ impl AllocBitmap {
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 {
@ -111,8 +117,8 @@ impl BitMapOps<usize> for AllocBitmap {
}
}
impl BitAnd for AllocBitmap {
type Output = Self;
impl BitAnd for &AllocBitmap {
type Output = AllocBitmap;
fn bitand(self, rhs: Self) -> Self::Output {
let mut result = AllocBitmap::new(self.elements);
@ -122,3 +128,11 @@ impl BitAnd for AllocBitmap {
result
}
}
impl BitAnd for AllocBitmap {
type Output = AllocBitmap;
fn bitand(self, rhs: Self) -> Self::Output {
&self & &rhs
}
}

View File

@ -663,3 +663,23 @@ fn test_alloc_bitmap_bitand_128() {
assert_eq!(bitmap3.first_false_index(), Some(2));
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));
}

View File

@ -4,6 +4,7 @@
/// @param x 目标u64
/// @return i32 bit-number(0..63) of the first (least significant) zero bit.
#[inline]
#[allow(dead_code)]
pub fn ffz(x: u64) -> i32 {
(!x).trailing_zeros() as i32
}

View File

@ -3,7 +3,6 @@ use system_error::SystemError;
use crate::{
driver::open_firmware::fdt::OpenFirmwareFdtDriver,
init::boot_params,
kdebug,
libs::align::page_align_up,
mm::{mmio_buddy::mmio_pool, MemoryManagementArch, PhysAddr},
};

View File

@ -1,7 +1,5 @@
use crate::arch::{
asm::csr::{
CSR_SCAUSE, CSR_SEPC, CSR_SSCRATCH, CSR_SSTATUS, CSR_STVAL, SR_FS_VS, SR_SPP, SR_SUM,
},
asm::csr::{CSR_SCAUSE, CSR_SEPC, CSR_SSCRATCH, CSR_SSTATUS, CSR_STVAL, SR_SPP},
cpu::LocalContext,
interrupt::TrapFrame,
};

View File

@ -5,9 +5,7 @@ use core::hint::spin_loop;
use system_error::SystemError;
use crate::{
arch::syscall::syscall_handler, driver::irqchip::riscv_intc::riscv_intc_irq, kdebug, kerror,
};
use crate::{arch::syscall::syscall_handler, driver::irqchip::riscv_intc::riscv_intc_irq, kerror};
use super::TrapFrame;

View File

@ -2,7 +2,7 @@ use riscv::register::{scause::Scause, sstatus::Sstatus};
use system_error::SystemError;
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},
libs::align::align_up,
};
@ -17,6 +17,9 @@ pub struct RiscV64InterruptArch;
impl InterruptArch for RiscV64InterruptArch {
unsafe fn arch_irq_init() -> Result<(), SystemError> {
Self::interrupt_disable();
riscv_sifive_plic_init()?;
// 注意intc的初始化必须在plic之后不然会导致plic无法关联上中断
riscv_intc_init()?;
Ok(())

View File

@ -43,6 +43,7 @@ pub struct RiscV64MMArch;
impl RiscV64MMArch {
/// 使远程cpu的TLB中指定地址范围的页失效
#[allow(dead_code)]
pub fn remote_invalidate_page(
cpu: ProcessorId,
address: VirtAddr,
@ -57,6 +58,7 @@ impl RiscV64MMArch {
}
/// 使指定远程cpu的TLB中所有范围的页失效
#[allow(dead_code)]
pub fn remote_invalidate_all(cpu: ProcessorId) -> Result<(), SbiRet> {
let r = Self::remote_invalidate_page(
cpu,

View File

@ -227,16 +227,23 @@ pub fn x86_vector_domain() -> &'static Arc<IrqDomain> {
#[inline(never)]
pub fn arch_early_irq_init() -> Result<(), SystemError> {
const IRQ_SIZE: u32 = 223;
let vec_domain = irq_domain_manager()
.create_and_add(
"VECTOR".to_string(),
&X86VectorDomainOps,
IrqNumber::new(32),
HardwareIrqNumber::new(32),
223,
IRQ_SIZE,
)
.ok_or(SystemError::ENOMEM)?;
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) };
let apic_chip = Arc::new(LocalApicChip::new());

View File

@ -32,6 +32,7 @@ use crate::{
VirtIODevice, VirtIODeviceIndex, VirtIODriver, VIRTIO_VENDOR_ID,
},
},
exception::{irqdesc::IrqReturn, IrqNumber},
filesystem::{kernfs::KernFSInode, mbr::MbrDiskPartionTable},
init::initcall::INITCALL_POSTCORE,
libs::{
@ -85,15 +86,15 @@ unsafe impl Sync for VirtIOBlkDevice {}
impl VirtIOBlkDevice {
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);
if let Err(e) = device_inner {
kerror!("VirtIOBlkDevice '{dev_id:?}' create failed: {:?}", e);
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 {
self_ref: self_ref.clone(),
dev_id,
@ -104,6 +105,7 @@ impl VirtIOBlkDevice {
virtio_index: None,
device_common: DeviceCommonData::default(),
kobject_common: KObjectCommonData::default(),
irq,
}),
});
@ -190,6 +192,7 @@ struct InnerVirtIOBlkDevice {
virtio_index: Option<VirtIODeviceIndex>,
device_common: DeviceCommonData,
kobject_common: KObjectCommonData,
irq: Option<IrqNumber>,
}
impl Debug for InnerVirtIOBlkDevice {
@ -199,11 +202,16 @@ impl Debug for InnerVirtIOBlkDevice {
}
impl VirtIODevice for VirtIOBlkDevice {
fn irq(&self) -> Option<IrqNumber> {
self.inner().irq
}
fn handle_irq(
&self,
_irq: crate::exception::IrqNumber,
) -> Result<crate::exception::irqdesc::IrqReturn, system_error::SystemError> {
todo!("VirtIOBlkDevice::handle_irq")
) -> Result<IrqReturn, system_error::SystemError> {
// todo: handle virtio blk irq
Ok(crate::exception::irqdesc::IrqReturn::Handled)
}
fn dev_id(&self) -> &Arc<DeviceId> {

View File

@ -6,14 +6,17 @@ use system_error::SystemError;
use crate::{
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::{
irqdata::{IrqHandlerData, IrqLineStatus},
irqdesc::{
irq_desc_manager, IrqDesc, IrqFlowHandler, IrqHandleFlags, IrqHandler, IrqReturn,
},
manage::irq_manager,
InterruptArch, IrqNumber,
HardwareIrqNumber, InterruptArch, IrqNumber,
},
libs::spinlock::SpinLock,
mm::percpu::PerCpu,
@ -42,7 +45,7 @@ static mut HART0_NSEC_PASSED: usize = 0;
static mut HART0_LAST_UPDATED: u64 = 0;
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> {
// 更新下一次中断时间
@ -117,7 +120,7 @@ pub fn riscv_sbi_timer_init_local() {
irq_manager()
.request_irq(
RiscVSbiTimer::TIMER_IRQ,
riscv_intc_hwirq_to_virq(RiscVSbiTimer::TIMER_IRQ).unwrap(),
"riscv_clocksource".to_string(),
&RiscvSbiTimerHandler,
IrqHandleFlags::IRQF_SHARED | IrqHandleFlags::IRQF_PERCPU,
@ -136,7 +139,8 @@ pub fn riscv_sbi_timer_init_local() {
#[inline(never)]
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.set_handler(&RiscvSbiTimerIrqFlowHandler);

View File

@ -1,2 +1,4 @@
#[cfg(target_arch = "riscv64")]
pub mod riscv_intc;
#[cfg(target_arch = "riscv64")]
pub mod riscv_sifive_plic;

View File

@ -17,6 +17,8 @@ use crate::{
sched::{SchedMode, __schedule},
};
use super::riscv_sifive_plic::do_plic_irq;
static mut RISCV_INTC_DOMAIN: Option<Arc<IrqDomain>> = 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() }
}
/// RISC-V INTC虚拟中断号的起始值192映射物理的0
pub const RISCV_INTC_VIRQ_START: u32 = 192;
#[derive(Debug)]
struct RiscvIntcChip {
inner: SpinLock<InnerIrqChip>,
@ -87,6 +92,7 @@ impl IrqChip for RiscvIntcChip {
}
impl RiscvIntcChip {
const IRQ_SIZE: u32 = 64;
fn new() -> Self {
Self {
inner: SpinLock::new(InnerIrqChip {
@ -143,7 +149,11 @@ pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
}
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(|| {
kerror!("Failed to create riscv-intc domain");
SystemError::ENXIO
@ -152,7 +162,7 @@ pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
irq_domain_manager().set_default_domain(intc_domain.clone());
unsafe {
RISCV_INTC_DOMAIN = Some(intc_domain);
RISCV_INTC_DOMAIN = Some(intc_domain.clone());
}
riscv_sbi_timer_irq_desc_init();
@ -160,12 +170,58 @@ pub unsafe fn riscv_intc_init() -> Result<(), SystemError> {
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
pub fn riscv_intc_irq(trap_frame: &mut TrapFrame) {
let hwirq = HardwareIrqNumber::new(trap_frame.cause.code() as u32);
// kdebug!("riscv64_do_irq: interrupt {hwirq:?}");
GenericIrqHandler::handle_domain_irq(riscv_intc_domain().clone().unwrap(), hwirq, trap_frame)
if hwirq.data() == 9 {
// external interrupt
do_plic_irq(trap_frame);
} else {
GenericIrqHandler::handle_domain_irq(
riscv_intc_domain().clone().unwrap(),
hwirq,
trap_frame,
)
.ok();
}
do_softirq();
if hwirq.data() == RiscVSbiTimer::TIMER_IRQ.data() {
__schedule(SchedMode::SM_PREEMPT);

View 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:?}");
}
}
}

View File

@ -207,6 +207,10 @@ impl VirtIODevice for VirtioInterface {
return Ok(IrqReturn::Handled);
}
fn irq(&self) -> Option<IrqNumber> {
None
}
fn dev_id(&self) -> &Arc<DeviceId> {
return &self.dev_id;
}

View File

@ -3,7 +3,16 @@ use hashbrown::HashMap;
use system_error::SystemError;
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;
@ -83,3 +92,36 @@ fn init_virtio_irq_manager() -> Result<(), SystemError> {
}
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);
}
}
}

View File

@ -36,6 +36,13 @@ pub trait VirtIODevice: Device {
/// virtio 设备厂商
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 {

View File

@ -8,16 +8,20 @@ use system_error::SystemError;
use unified_init::macros::unified_init;
use crate::{
driver::base::{
device::{
bus::{bus_manager, Bus},
device_manager,
driver::{driver_manager, Driver},
Device,
driver::{
base::{
device::{
bus::{bus_manager, Bus},
device_manager,
driver::{driver_manager, Driver},
Device,
},
kobject::KObject,
subsys::SubSysPrivate,
},
kobject::KObject,
subsys::SubSysPrivate,
virtio::irq::{virtio_irq_manager, DefaultVirtioIrqHandler},
},
exception::{irqdesc::IrqHandleFlags, manage::irq_manager},
filesystem::{
sysfs::{
file::sysfs_emit_str, Attribute, AttributeGroup, SysFSOpsSupport, SYSFS_ATTR_MODE_RO,
@ -175,7 +179,47 @@ impl VirtIODeviceManager {
virtio_drv.probe(&dev)?;
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)]

View File

@ -1,5 +1,7 @@
use virtio_drivers::transport::Transport;
use crate::exception::HardwareIrqNumber;
use super::{transport_mmio::VirtIOMmioTransport, transport_pci::PciTransport};
pub enum VirtIOTransport {
@ -7,6 +9,15 @@ pub enum VirtIOTransport {
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 {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {

View File

@ -8,9 +8,6 @@ use crate::driver::pci::pci::{
use crate::driver::pci::pci_irq::{IrqCommonMsg, IrqSpecificMsg, PciInterrupt, PciIrqMsg, IRQ};
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;
@ -26,12 +23,12 @@ use core::{
mem::{align_of, size_of},
ptr::{self, addr_of_mut, NonNull},
};
use system_error::SystemError;
use virtio_drivers::{
transport::{DeviceStatus, DeviceType, Transport},
Error, Hal, PhysAddr,
};
use super::irq::DefaultVirtioIrqHandler;
use super::VIRTIO_VENDOR_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]> {
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);
}
}
}

View File

@ -5,13 +5,14 @@ use system_error::SystemError;
use crate::{
arch::{interrupt::TrapFrame, CurrentIrqArch},
exception::irqdesc::InnerIrqDesc,
exception::{irqchip::IrqChipFlags, irqdesc::InnerIrqDesc},
libs::{once::Once, spinlock::SpinLockGuard},
process::{ProcessFlags, ProcessManager},
smp::core::smp_get_processor_id,
};
use super::{
irqchip::IrqChip,
irqdata::{IrqData, IrqHandlerData, IrqStatus},
irqdesc::{
InnerIrqAction, IrqDesc, IrqDescState, IrqFlowHandler, IrqReturn, ThreadedHandlerFlags,
@ -34,6 +35,7 @@ pub fn fast_eoi_irq_handler() -> &'static dyn IrqFlowHandler {
/// 获取用于处理边沿触发中断的处理程序
#[inline(always)]
#[allow(dead_code)]
pub fn edge_irq_handler() -> &'static dyn IrqFlowHandler {
&EdgeIrqHandler
}
@ -55,9 +57,38 @@ impl IrqFlowHandler for HandleBadIrq {
struct 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
todo!("FastEOIIrqHandler");
/// 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) {
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");
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();
desc_inner_guard = handle_irq_event(irq_desc, desc_inner_guard);
if !desc_inner_guard
.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 {
pub(super) fn do_irq_wake_thread(
&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
@ -228,6 +290,47 @@ fn do_handle_irq_event(desc: &Arc<IrqDesc>) -> Result<(), SystemError> {
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>) {
// warn on once
if action_inner

View File

@ -37,27 +37,27 @@ use super::{
pub trait IrqChip: Sync + Send + Any + Debug {
fn name(&self) -> &'static str;
/// 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)
}
/// 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)
}
/// enable the interrupt
///
/// (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)
}
/// disable the interrupt
fn irq_disable(&self, irq: &Arc<IrqData>);
fn irq_disable(&self, irq_data: &Arc<IrqData>);
/// start of a new interrupt
fn irq_ack(&self, irq: &Arc<IrqData>);
fn irq_ack(&self, irq_data: &Arc<IrqData>);
/// mask an interrupt source
///
@ -66,7 +66,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
/// 如果返回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)
}
@ -74,18 +74,18 @@ pub trait IrqChip: Sync + Send + Any + Debug {
fn can_mask_ack(&self) -> bool;
/// 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
///
/// 用于取消屏蔽中断
///
/// 如果返回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)
}
/// end of interrupt
fn irq_eoi(&self, _irq: &Arc<IrqData>) {}
fn irq_eoi(&self, _irq_data: &Arc<IrqData>) {}
/// 指示当前芯片是否可以设置中断亲和性。
fn can_set_affinity(&self) -> bool;
@ -96,7 +96,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
/// 不需要对提供的亲和性掩码进行完整性检查。这用于CPU热插拔其中目标CPU尚未在cpu_online_mask中设置。
fn irq_set_affinity(
&self,
_irq: &Arc<IrqData>,
_irq_data: &Arc<IrqData>,
_cpu: &CpuMask,
_force: bool,
) -> Result<IrqChipSetMaskResult, SystemError> {
@ -104,7 +104,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
}
/// 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)
}
@ -119,65 +119,65 @@ pub trait IrqChip: Sync + Send + Any + Debug {
///
fn irq_set_type(
&self,
_irq: &Arc<IrqData>,
_irq_data: &Arc<IrqData>,
_flow_type: IrqLineStatus,
) -> Result<IrqChipSetMaskResult, SystemError> {
Err(SystemError::ENOSYS)
}
/// 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)
}
/// 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(())
}
/// 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(())
}
/// function called from core code on suspend once per
/// 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,
/// 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
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
fn irq_calc_mask(&self, _irq: &Arc<IrqData>) {}
fn irq_calc_mask(&self, _irq_data: &Arc<IrqData>) {}
// todo: print chip
/// optional to request resources before calling
/// 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(())
}
/// optional to release resources acquired with
/// 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
///
/// 组装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
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
fn irqchip_state(
&self,
_irq: &Arc<IrqData>,
_irq_data: &Arc<IrqData>,
_which: IrqChipState,
) -> Result<bool, SystemError> {
Err(SystemError::ENOSYS)
@ -186,7 +186,7 @@ pub trait IrqChip: Sync + Send + Any + Debug {
/// set the internal state of an interrupt
fn set_irqchip_state(
&self,
_irq: &Arc<IrqData>,
_irq_data: &Arc<IrqData>,
_which: IrqChipState,
_state: bool,
) -> Result<(), SystemError> {
@ -196,17 +196,17 @@ pub trait IrqChip: Sync + Send + Any + Debug {
// todo: set vcpu affinity
/// 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
/// 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)
}
/// 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;
}

View File

@ -80,6 +80,7 @@ impl IrqData {
self.inner.lock_irqsave().desc = desc;
}
#[allow(dead_code)]
pub fn clear_irq_desc(&self) {
self.inner.lock_irqsave().desc = Weak::new();
}
@ -210,6 +211,7 @@ impl IrqCommonData {
handler_data: None,
msi_desc: None,
affinity: CpuMask::new(),
effective_affinity: CpuMask::new(),
};
return IrqCommonData {
inner: SpinLock::new(inner),
@ -304,6 +306,10 @@ impl IrqCommonData {
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> {
self.inner.lock_irqsave()
}
@ -318,6 +324,7 @@ pub struct InnerIrqCommonData {
handler_data: Option<Arc<dyn IrqHandlerData>>,
msi_desc: Option<Arc<MsiDesc>>,
affinity: CpuMask,
effective_affinity: CpuMask,
}
impl InnerIrqCommonData {
@ -338,6 +345,10 @@ impl InnerIrqCommonData {
pub fn handler_data(&self) -> Option<Arc<dyn IrqHandlerData>> {
self.handler_data.clone()
}
pub fn effective_affinity(&self) -> &CpuMask {
&self.effective_affinity
}
}
/// 中断处理函数传入的数据

View File

@ -114,6 +114,7 @@ impl IrqDesc {
kern_inode: None,
kset: None,
parent_kobj: None,
threads_oneshot: 0,
}),
request_mutex: Mutex::new(()),
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) {
let mut desc_guard = self.inner();
desc_guard.line_status.remove(clear);
@ -365,6 +374,8 @@ pub struct InnerIrqDesc {
/// per-cpu affinity
percpu_affinity: Option<CpuMask>,
// wait_for_threads: EventWaitQueue
/// bitfield to handle shared oneshot threads
threads_oneshot: u64,
}
impl InnerIrqDesc {
@ -444,6 +455,10 @@ impl InnerIrqDesc {
!self.line_status.contains(IrqLineStatus::IRQ_NOTHREAD)
}
pub fn threads_oneshot(&self) -> u64 {
self.threads_oneshot
}
/// 中断是否可以设置CPU亲和性
pub fn can_set_affinity(&self) -> bool {
if !self.common_data.status().can_balance()

View File

@ -110,8 +110,6 @@ impl IrqDomainManager {
self.add_domain(domain.clone());
self.domain_associate_many(&domain, first_irq, first_hwirq, irq_size);
return Some(domain);
}
@ -248,6 +246,10 @@ impl IrqDomainManager {
/// 这是调用 domain_ops->activate 以编程中断控制器的第二步,以便中断实际上可以被传递。
pub fn activate_irq(&self, irq_data: &Arc<IrqData>, reserve: bool) -> Result<(), SystemError> {
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() {
r = self.do_activate_irq(Some(irq_data.clone()), reserve);
}
@ -268,7 +270,9 @@ impl IrqDomainManager {
let mut r = Ok(());
if let Some(irq_data) = irq_data {
// kdebug!("do_activate_irq: irq_data={:?}", irq_data);
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());
if let Some(parent_data) = parent_data.clone() {
r = self.do_activate_irq(Some(parent_data), reserve);

View File

@ -155,7 +155,7 @@ impl IrqManager {
*action_guard.flags_mut() = flags;
*action_guard.dev_id_mut() = dev_id;
drop(action_guard);
kdebug!("to inner_setup_irq");
return self.inner_setup_irq(irq, irqaction, desc);
}
@ -370,6 +370,15 @@ impl IrqManager {
|| ((old_guard.flags().bitxor(*action_guard.flags()))
.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(
old_guard,
desc_inner_guard,
@ -383,6 +392,12 @@ impl IrqManager {
if *old_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(
old_guard,
desc_inner_guard,
@ -436,6 +451,13 @@ impl IrqManager {
if let Err(e) =
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(
e,
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.
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(
e,
desc_inner_guard,
@ -599,6 +628,11 @@ impl IrqManager {
desc_inner_guard: &mut SpinLockGuard<'_, InnerIrqDesc>,
resend: bool,
) -> 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_startup(desc, desc_inner_guard, resend, Self::IRQ_START_FORCE)
}
@ -625,6 +659,11 @@ impl IrqManager {
resend: bool,
force: bool,
) -> Result<(), SystemError> {
kdebug!(
"irq_startup: irq: {}, name: {:?}",
desc_inner_guard.irq_data().irq().data(),
desc_inner_guard.name()
);
let mut ret = Ok(());
let irq_data = desc_inner_guard.irq_data().clone();
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,
irq_data: &Arc<IrqData>,
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>>) {
kwarn!("Unimplemented free_irq");
}

View File

@ -16,6 +16,21 @@ impl CpuMask {
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
pub fn first(&self) -> Option<ProcessorId> {
self.bmp
@ -86,14 +101,24 @@ impl CpuMask {
pub fn inner(&self) -> &AllocBitmap {
&self.bmp
}
pub fn bitand_assign(&mut self, rhs: &CpuMask) {
self.bmp.bitand_assign(&rhs.bmp);
}
}
impl BitAnd for CpuMask {
type Output = Self;
impl BitAnd for &CpuMask {
type Output = CpuMask;
fn bitand(self, rhs: Self) -> Self::Output {
let bmp = self.bmp & rhs.bmp;
Self { bmp }
fn bitand(self, rhs: &CpuMask) -> Self::Output {
let bmp = &self.bmp & &rhs.bmp;
CpuMask { bmp }
}
}
impl Default for CpuMask {
fn default() -> Self {
Self::new()
}
}

View File

@ -1,3 +1,4 @@
use crate::libs::align::{page_align_down, page_align_up};
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
use crate::mm::kernel_mapper::KernelMapper;
use crate::mm::page::{PAGE_1G_SHIFT, PAGE_4K_SHIFT};
@ -682,6 +683,41 @@ impl MMIOSpaceGuard {
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不会释放映射的空间
pub unsafe fn leak(self) {
core::mem::forget(self);

View File

@ -64,6 +64,7 @@ impl CpuHpCpuState {
}
}
#[allow(dead_code)]
pub const fn thread(&self) -> &Option<Arc<ProcessControlBlock>> {
&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_present_cpu(boot_cpu, true) };
SmpCpuManager::arch_init(boot_cpu);
}