Skip to content

Commit

Permalink
feat:(riscv/intr) 实现riscv plic驱动,能处理外部中断 (#799)
Browse files Browse the repository at this point in the history
* feat:(riscv/intr) 实现riscv plic驱动,能处理外部中断

- 实现riscv plic驱动,能处理外部中断
- 能收到virtio-blk的中断
- 实现fasteoi interrupt handler
  • Loading branch information
fslongjin authored May 1, 2024
1 parent 17dc558 commit 0102d69
Show file tree
Hide file tree
Showing 30 changed files with 1,214 additions and 127 deletions.
4 changes: 2 additions & 2 deletions kernel/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
18 changes: 16 additions & 2 deletions kernel/crates/bitmap/src/alloc_bitmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
Expand All @@ -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
}
}
20 changes: 20 additions & 0 deletions kernel/crates/bitmap/tests/alloc-bitmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
1 change: 1 addition & 0 deletions kernel/src/arch/riscv64/asm/bitops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
1 change: 0 additions & 1 deletion kernel/src/arch/riscv64/driver/of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
};
Expand Down
4 changes: 1 addition & 3 deletions kernel/src/arch/riscv64/interrupt/entry.rs
Original file line number Diff line number Diff line change
@@ -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,
};
Expand Down
4 changes: 1 addition & 3 deletions kernel/src/arch/riscv64/interrupt/handle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
5 changes: 4 additions & 1 deletion kernel/src/arch/riscv64/interrupt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand All @@ -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(())
Expand Down
2 changes: 2 additions & 0 deletions kernel/src/arch/riscv64/mm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ pub struct RiscV64MMArch;

impl RiscV64MMArch {
/// 使远程cpu的TLB中,指定地址范围的页失效
#[allow(dead_code)]
pub fn remote_invalidate_page(
cpu: ProcessorId,
address: VirtAddr,
Expand All @@ -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,
Expand Down
9 changes: 8 additions & 1 deletion kernel/src/arch/x86_64/driver/apic/lapic_vector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
18 changes: 13 additions & 5 deletions kernel/src/driver/block/virtio_blk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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,
Expand All @@ -104,6 +105,7 @@ impl VirtIOBlkDevice {
virtio_index: None,
device_common: DeviceCommonData::default(),
kobject_common: KObjectCommonData::default(),
irq,
}),
});

Expand Down Expand Up @@ -190,6 +192,7 @@ struct InnerVirtIOBlkDevice {
virtio_index: Option<VirtIODeviceIndex>,
device_common: DeviceCommonData,
kobject_common: KObjectCommonData,
irq: Option<IrqNumber>,
}

impl Debug for InnerVirtIOBlkDevice {
Expand All @@ -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> {
Expand Down
14 changes: 9 additions & 5 deletions kernel/src/driver/clocksource/timer_riscv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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> {
// 更新下一次中断时间
Expand Down Expand Up @@ -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,
Expand All @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions kernel/src/driver/irqchip/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
#[cfg(target_arch = "riscv64")]
pub mod riscv_intc;
#[cfg(target_arch = "riscv64")]
pub mod riscv_sifive_plic;
64 changes: 60 additions & 4 deletions kernel/src/driver/irqchip/riscv_intc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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>,
Expand Down Expand Up @@ -87,6 +92,7 @@ impl IrqChip for RiscvIntcChip {
}

impl RiscvIntcChip {
const IRQ_SIZE: u32 = 64;
fn new() -> Self {
Self {
inner: SpinLock::new(InnerIrqChip {
Expand Down Expand Up @@ -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
Expand All @@ -152,20 +162,66 @@ 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();

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);
Expand Down
Loading

0 comments on commit 0102d69

Please sign in to comment.